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
path: root/source
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
Filling in branch from trunk
Diffstat (limited to 'source')
-rw-r--r--source/CMakeLists.txt38
-rw-r--r--source/Makefile648
-rw-r--r--source/SConscript11
-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
-rw-r--r--source/creator/CMakeLists.txt276
-rw-r--r--source/creator/Makefile66
-rw-r--r--source/creator/SConscript18
-rw-r--r--source/creator/buildinfo.c46
-rw-r--r--source/creator/creator.c734
-rw-r--r--source/darwin/Makefile58
-rw-r--r--source/darwin/blender.app/Contents/Info.plist53
-rw-r--r--source/darwin/blender.app/Contents/MacOS/blender1
-rw-r--r--source/darwin/blender.app/Contents/PkgInfo1
-rw-r--r--source/darwin/blender.app/Contents/Resources/blender file icon.icnsbin0 -> 48363 bytes
-rw-r--r--source/darwin/blender.app/Contents/Resources/blender icon.icnsbin0 -> 43688 bytes
-rw-r--r--source/darwin/blendercreator.app/Contents/Info.plist53
-rw-r--r--source/darwin/blendercreator.app/Contents/MacOS/blendercreator1
-rw-r--r--source/darwin/blendercreator.app/Contents/PkgInfo1
-rw-r--r--source/darwin/blendercreator.app/Contents/Resources/blender creator icon.icnsbin0 -> 43688 bytes
-rw-r--r--source/darwin/blendercreator.app/Contents/Resources/blender file icon.icnsbin0 -> 48363 bytes
-rw-r--r--source/darwin/blenderplayer.app/Contents/Info.plist47
-rw-r--r--source/darwin/blenderplayer.app/Contents/MacOS/blenderplayer1
-rw-r--r--source/darwin/blenderplayer.app/Contents/PkgInfo1
-rw-r--r--source/darwin/blenderplayer.app/Contents/Resources/blender file icon.icnsbin0 -> 48363 bytes
-rw-r--r--source/darwin/blenderplayer.app/Contents/Resources/blender player icon.icnsbin0 -> 43688 bytes
-rw-r--r--source/darwin/blenderpublisher.app/Contents/Info.plist53
-rw-r--r--source/darwin/blenderpublisher.app/Contents/MacOS/blenderpublisher1
-rw-r--r--source/darwin/blenderpublisher.app/Contents/PkgInfo1
-rw-r--r--source/darwin/blenderpublisher.app/Contents/Resources/blender file icon.icnsbin0 -> 1721 bytes
-rw-r--r--source/darwin/blenderpublisher.app/Contents/Resources/blender publisher icon.icnsbin0 -> 1991 bytes
-rw-r--r--source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp668
-rw-r--r--source/gameengine/BlenderRoutines/CMakeLists.txt40
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp165
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.h171
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderGL.cpp316
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderGL.h65
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderInputDevice.cpp37
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h223
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp172
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.h52
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.cpp180
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.h50
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.cpp117
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.h102
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp478
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h109
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderSystem.cpp59
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderSystem.h51
-rw-r--r--source/gameengine/BlenderRoutines/Makefile77
-rw-r--r--source/gameengine/BlenderRoutines/SConscript28
-rw-r--r--source/gameengine/CMakeLists.txt50
-rw-r--r--source/gameengine/Converter/BL_ActionActuator.cpp907
-rw-r--r--source/gameengine/Converter/BL_ActionActuator.h154
-rw-r--r--source/gameengine/Converter/BL_ArmatureObject.cpp207
-rw-r--r--source/gameengine/Converter/BL_ArmatureObject.h92
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp2270
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.h56
-rw-r--r--source/gameengine/Converter/BL_DeformableGameObject.cpp65
-rw-r--r--source/gameengine/Converter/BL_DeformableGameObject.h67
-rw-r--r--source/gameengine/Converter/BL_MeshDeformer.cpp159
-rw-r--r--source/gameengine/Converter/BL_MeshDeformer.h80
-rw-r--r--source/gameengine/Converter/BL_SkinDeformer.cpp191
-rw-r--r--source/gameengine/Converter/BL_SkinDeformer.h110
-rw-r--r--source/gameengine/Converter/BL_SkinMeshObject.cpp157
-rw-r--r--source/gameengine/Converter/BL_SkinMeshObject.h181
-rw-r--r--source/gameengine/Converter/BlenderWorldInfo.cpp237
-rw-r--r--source/gameengine/Converter/BlenderWorldInfo.h103
-rw-r--r--source/gameengine/Converter/CMakeLists.txt76
-rw-r--r--source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp84
-rw-r--r--source/gameengine/Converter/KX_BlenderScalarInterpolator.h70
-rw-r--r--source/gameengine/Converter/KX_BlenderSceneConverter.cpp993
-rw-r--r--source/gameengine/Converter/KX_BlenderSceneConverter.h149
-rw-r--r--source/gameengine/Converter/KX_ConvertActuators.cpp862
-rw-r--r--source/gameengine/Converter/KX_ConvertActuators.h49
-rw-r--r--source/gameengine/Converter/KX_ConvertControllers.cpp182
-rw-r--r--source/gameengine/Converter/KX_ConvertControllers.h50
-rw-r--r--source/gameengine/Converter/KX_ConvertProperties.cpp137
-rw-r--r--source/gameengine/Converter/KX_ConvertProperties.h42
-rw-r--r--source/gameengine/Converter/KX_ConvertSensors.cpp740
-rw-r--r--source/gameengine/Converter/KX_ConvertSensors.h47
-rw-r--r--source/gameengine/Converter/KX_IpoConvert.cpp757
-rw-r--r--source/gameengine/Converter/KX_IpoConvert.h58
-rw-r--r--source/gameengine/Converter/Makefile66
-rw-r--r--source/gameengine/Converter/SConscript25
-rw-r--r--source/gameengine/Expressions/BoolValue.cpp214
-rw-r--r--source/gameengine/Expressions/BoolValue.h52
-rw-r--r--source/gameengine/Expressions/CMakeLists.txt41
-rw-r--r--source/gameengine/Expressions/ConstExpr.cpp132
-rw-r--r--source/gameengine/Expressions/ConstExpr.h47
-rw-r--r--source/gameengine/Expressions/EXP_C-Api.cpp127
-rw-r--r--source/gameengine/Expressions/EXP_C-Api.h68
-rw-r--r--source/gameengine/Expressions/EmptyValue.cpp127
-rw-r--r--source/gameengine/Expressions/EmptyValue.h40
-rw-r--r--source/gameengine/Expressions/ErrorValue.cpp123
-rw-r--r--source/gameengine/Expressions/ErrorValue.h39
-rw-r--r--source/gameengine/Expressions/Expression.cpp76
-rw-r--r--source/gameengine/Expressions/Expression.h132
-rw-r--r--source/gameengine/Expressions/FloatValue.cpp316
-rw-r--r--source/gameengine/Expressions/FloatValue.h48
-rw-r--r--source/gameengine/Expressions/IdentifierExpr.cpp106
-rw-r--r--source/gameengine/Expressions/IdentifierExpr.h55
-rw-r--r--source/gameengine/Expressions/IfExpr.cpp144
-rw-r--r--source/gameengine/Expressions/IfExpr.h50
-rw-r--r--source/gameengine/Expressions/InputParser.cpp654
-rw-r--r--source/gameengine/Expressions/InputParser.h106
-rw-r--r--source/gameengine/Expressions/IntValue.cpp327
-rw-r--r--source/gameengine/Expressions/IntValue.h60
-rw-r--r--source/gameengine/Expressions/KX_HashedPtr.cpp66
-rw-r--r--source/gameengine/Expressions/KX_HashedPtr.h53
-rw-r--r--source/gameengine/Expressions/KX_Python.h58
-rw-r--r--source/gameengine/Expressions/KX_Python_dynamic.h39
-rw-r--r--source/gameengine/Expressions/KX_Python_static.h39
-rw-r--r--source/gameengine/Expressions/ListValue.cpp563
-rw-r--r--source/gameengine/Expressions/ListValue.h77
-rw-r--r--source/gameengine/Expressions/Makefile46
-rw-r--r--source/gameengine/Expressions/Operator1Expr.cpp152
-rw-r--r--source/gameengine/Expressions/Operator1Expr.h52
-rw-r--r--source/gameengine/Expressions/Operator2Expr.cpp277
-rw-r--r--source/gameengine/Expressions/Operator2Expr.h59
-rw-r--r--source/gameengine/Expressions/PyObjectPlus.cpp178
-rw-r--r--source/gameengine/Expressions/PyObjectPlus.h188
-rw-r--r--source/gameengine/Expressions/SConscript9
-rw-r--r--source/gameengine/Expressions/StringValue.cpp140
-rw-r--r--source/gameengine/Expressions/StringValue.h52
-rw-r--r--source/gameengine/Expressions/Value.cpp769
-rw-r--r--source/gameengine/Expressions/Value.h442
-rw-r--r--source/gameengine/Expressions/VectorValue.cpp217
-rw-r--r--source/gameengine/Expressions/VectorValue.h85
-rw-r--r--source/gameengine/Expressions/VoidValue.h68
-rw-r--r--source/gameengine/GameLogic/CMakeLists.txt43
-rw-r--r--source/gameengine/GameLogic/Joystick/Makefile47
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp374
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_Joystick.h388
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h52
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp73
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h52
-rw-r--r--source/gameengine/GameLogic/Makefile50
-rw-r--r--source/gameengine/GameLogic/SCA_ANDController.cpp147
-rw-r--r--source/gameengine/GameLogic/SCA_ANDController.h59
-rw-r--r--source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp69
-rw-r--r--source/gameengine/GameLogic/SCA_AlwaysEventManager.h51
-rw-r--r--source/gameengine/GameLogic/SCA_AlwaysSensor.cpp142
-rw-r--r--source/gameengine/GameLogic/SCA_AlwaysSensor.h62
-rw-r--r--source/gameengine/GameLogic/SCA_EventManager.cpp83
-rw-r--r--source/gameengine/GameLogic/SCA_EventManager.h73
-rw-r--r--source/gameengine/GameLogic/SCA_ExpressionController.cpp164
-rw-r--r--source/gameengine/GameLogic/SCA_ExpressionController.h64
-rw-r--r--source/gameengine/GameLogic/SCA_IActuator.cpp114
-rw-r--r--source/gameengine/GameLogic/SCA_IActuator.h83
-rw-r--r--source/gameengine/GameLogic/SCA_IController.cpp123
-rw-r--r--source/gameengine/GameLogic/SCA_IController.h58
-rw-r--r--source/gameengine/GameLogic/SCA_IInputDevice.cpp138
-rw-r--r--source/gameengine/GameLogic/SCA_IInputDevice.h312
-rw-r--r--source/gameengine/GameLogic/SCA_ILogicBrick.cpp324
-rw-r--r--source/gameengine/GameLogic/SCA_ILogicBrick.h112
-rw-r--r--source/gameengine/GameLogic/SCA_IObject.cpp354
-rw-r--r--source/gameengine/GameLogic/SCA_IObject.h129
-rw-r--r--source/gameengine/GameLogic/SCA_IScene.cpp69
-rw-r--r--source/gameengine/GameLogic/SCA_IScene.h66
-rw-r--r--source/gameengine/GameLogic/SCA_ISensor.cpp334
-rw-r--r--source/gameengine/GameLogic/SCA_ISensor.h129
-rw-r--r--source/gameengine/GameLogic/SCA_JoystickManager.cpp84
-rw-r--r--source/gameengine/GameLogic/SCA_JoystickManager.h57
-rw-r--r--source/gameengine/GameLogic/SCA_JoystickSensor.cpp476
-rw-r--r--source/gameengine/GameLogic/SCA_JoystickSensor.h127
-rw-r--r--source/gameengine/GameLogic/SCA_KeyboardManager.cpp90
-rw-r--r--source/gameengine/GameLogic/SCA_KeyboardManager.h66
-rw-r--r--source/gameengine/GameLogic/SCA_KeyboardSensor.cpp678
-rw-r--r--source/gameengine/GameLogic/SCA_KeyboardSensor.h159
-rw-r--r--source/gameengine/GameLogic/SCA_LogicManager.cpp487
-rw-r--r--source/gameengine/GameLogic/SCA_LogicManager.h163
-rw-r--r--source/gameengine/GameLogic/SCA_MouseManager.cpp120
-rw-r--r--source/gameengine/GameLogic/SCA_MouseManager.h73
-rw-r--r--source/gameengine/GameLogic/SCA_MouseSensor.cpp285
-rw-r--r--source/gameengine/GameLogic/SCA_MouseSensor.h123
-rw-r--r--source/gameengine/GameLogic/SCA_ORController.cpp139
-rw-r--r--source/gameengine/GameLogic/SCA_ORController.h59
-rw-r--r--source/gameengine/GameLogic/SCA_PropertyActuator.cpp288
-rw-r--r--source/gameengine/GameLogic/SCA_PropertyActuator.h100
-rw-r--r--source/gameengine/GameLogic/SCA_PropertyEventManager.cpp69
-rw-r--r--source/gameengine/GameLogic/SCA_PropertyEventManager.h54
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.cpp433
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.h111
-rw-r--r--source/gameengine/GameLogic/SCA_PythonController.cpp448
-rw-r--r--source/gameengine/GameLogic/SCA_PythonController.h92
-rw-r--r--source/gameengine/GameLogic/SCA_RandomActuator.cpp642
-rw-r--r--source/gameengine/GameLogic/SCA_RandomActuator.h145
-rw-r--r--source/gameengine/GameLogic/SCA_RandomEventManager.cpp68
-rw-r--r--source/gameengine/GameLogic/SCA_RandomEventManager.h55
-rw-r--r--source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp129
-rw-r--r--source/gameengine/GameLogic/SCA_RandomNumberGenerator.h65
-rw-r--r--source/gameengine/GameLogic/SCA_RandomSensor.cpp195
-rw-r--r--source/gameengine/GameLogic/SCA_RandomSensor.h76
-rw-r--r--source/gameengine/GameLogic/SCA_TimeEventManager.cpp114
-rw-r--r--source/gameengine/GameLogic/SCA_TimeEventManager.h56
-rw-r--r--source/gameengine/GameLogic/SConscript12
-rw-r--r--source/gameengine/GamePlayer/CMakeLists.txt30
-rw-r--r--source/gameengine/GamePlayer/Makefile60
-rw-r--r--source/gameengine/GamePlayer/SConscript3
-rw-r--r--source/gameengine/GamePlayer/common/CMakeLists.txt82
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Canvas.cpp493
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Canvas.h273
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Engine.cpp342
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Engine.h129
-rw-r--r--source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp127
-rw-r--r--source/gameengine/GamePlayer/common/GPC_KeyboardDevice.h91
-rw-r--r--source/gameengine/GamePlayer/common/GPC_MouseDevice.cpp216
-rw-r--r--source/gameengine/GamePlayer/common/GPC_MouseDevice.h107
-rw-r--r--source/gameengine/GamePlayer/common/GPC_PolygonMaterial.cpp421
-rw-r--r--source/gameengine/GamePlayer/common/GPC_PolygonMaterial.h92
-rw-r--r--source/gameengine/GamePlayer/common/GPC_RawImage.cpp138
-rw-r--r--source/gameengine/GamePlayer/common/GPC_RawImage.h122
-rw-r--r--source/gameengine/GamePlayer/common/GPC_RawLoadDotBlendArray.cpp9313
-rw-r--r--source/gameengine/GamePlayer/common/GPC_RawLoadDotBlendArray.h39
-rw-r--r--source/gameengine/GamePlayer/common/GPC_RawLogoArrays.cpp1463
-rw-r--r--source/gameengine/GamePlayer/common/GPC_RawLogoArrays.h43
-rw-r--r--source/gameengine/GamePlayer/common/GPC_RenderTools.cpp596
-rw-r--r--source/gameengine/GamePlayer/common/GPC_RenderTools.h178
-rw-r--r--source/gameengine/GamePlayer/common/GPC_System.cpp93
-rw-r--r--source/gameengine/GamePlayer/common/GPC_System.h64
-rw-r--r--source/gameengine/GamePlayer/common/Makefile89
-rw-r--r--source/gameengine/GamePlayer/common/SConscript72
-rw-r--r--source/gameengine/GamePlayer/common/bmfont.cpp305
-rw-r--r--source/gameengine/GamePlayer/common/load.blendbin0 -> 60988 bytes
-rw-r--r--source/gameengine/GamePlayer/common/logo_blender.rawbin0 -> 14720 bytes
-rw-r--r--source/gameengine/GamePlayer/common/logo_blender3d.rawbin0 -> 5984 bytes
-rw-r--r--source/gameengine/GamePlayer/common/logo_nan.rawbin0 -> 3968 bytes
-rw-r--r--source/gameengine/GamePlayer/common/unix/GPU_Canvas.cpp75
-rw-r--r--source/gameengine/GamePlayer/common/unix/GPU_Canvas.h61
-rw-r--r--source/gameengine/GamePlayer/common/unix/GPU_Engine.cpp309
-rw-r--r--source/gameengine/GamePlayer/common/unix/GPU_Engine.h64
-rw-r--r--source/gameengine/GamePlayer/common/unix/GPU_KeyboardDevice.cpp136
-rw-r--r--source/gameengine/GamePlayer/common/unix/GPU_KeyboardDevice.h64
-rw-r--r--source/gameengine/GamePlayer/common/unix/GPU_PolygonMaterial.h56
-rw-r--r--source/gameengine/GamePlayer/common/unix/GPU_System.cpp58
-rw-r--r--source/gameengine/GamePlayer/common/unix/GPU_System.h49
-rw-r--r--source/gameengine/GamePlayer/common/unix/Makefile77
-rw-r--r--source/gameengine/GamePlayer/common/windows/GPW_Canvas.cpp178
-rw-r--r--source/gameengine/GamePlayer/common/windows/GPW_Canvas.h118
-rw-r--r--source/gameengine/GamePlayer/common/windows/GPW_Engine.cpp123
-rw-r--r--source/gameengine/GamePlayer/common/windows/GPW_Engine.h48
-rw-r--r--source/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.cpp283
-rw-r--r--source/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.h69
-rw-r--r--source/gameengine/GamePlayer/common/windows/GPW_System.cpp95
-rw-r--r--source/gameengine/GamePlayer/common/windows/GPW_System.h61
-rw-r--r--source/gameengine/GamePlayer/common/windows/Makefile66
-rw-r--r--source/gameengine/GamePlayer/ghost/CMakeLists.txt75
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.cpp859
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.h149
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp111
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Canvas.h65
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.cpp158
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.h58
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_System.cpp57
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_System.h56
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_ghost.cpp768
-rw-r--r--source/gameengine/GamePlayer/ghost/Makefile83
-rw-r--r--source/gameengine/GamePlayer/ghost/SConscript49
-rw-r--r--source/gameengine/Ketsji/BL_Material.cpp152
-rw-r--r--source/gameengine/Ketsji/BL_Material.h177
-rw-r--r--source/gameengine/Ketsji/BL_Shader.cpp1470
-rw-r--r--source/gameengine/Ketsji/BL_Shader.h234
-rw-r--r--source/gameengine/Ketsji/BL_Texture.cpp723
-rw-r--r--source/gameengine/Ketsji/BL_Texture.h64
-rw-r--r--source/gameengine/Ketsji/CMakeLists.txt70
-rw-r--r--source/gameengine/Ketsji/KXNetwork/CMakeLists.txt44
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp96
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h60
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp212
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h77
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp296
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h89
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.cpp35
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.h32
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.cpp36
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.h32
-rw-r--r--source/gameengine/Ketsji/KXNetwork/Makefile49
-rw-r--r--source/gameengine/Ketsji/KXNetwork/SConscript12
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.cpp771
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.h118
-rw-r--r--source/gameengine/Ketsji/KX_BulletPhysicsController.cpp247
-rw-r--r--source/gameengine/Ketsji/KX_BulletPhysicsController.h70
-rw-r--r--source/gameengine/Ketsji/KX_CDActuator.cpp256
-rw-r--r--source/gameengine/Ketsji/KX_CDActuator.h97
-rw-r--r--source/gameengine/Ketsji/KX_Camera.cpp761
-rw-r--r--source/gameengine/Ketsji/KX_Camera.h261
-rw-r--r--source/gameengine/Ketsji/KX_CameraActuator.cpp526
-rw-r--r--source/gameengine/Ketsji/KX_CameraActuator.h140
-rw-r--r--source/gameengine/Ketsji/KX_CameraIpoSGController.cpp129
-rw-r--r--source/gameengine/Ketsji/KX_CameraIpoSGController.h93
-rw-r--r--source/gameengine/Ketsji/KX_ClientObjectInfo.h83
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintActuator.cpp377
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintActuator.h110
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintWrapper.cpp137
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintWrapper.h58
-rw-r--r--source/gameengine/Ketsji/KX_ConvertPhysicsObject.h148
-rw-r--r--source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp1205
-rw-r--r--source/gameengine/Ketsji/KX_EmptyObject.cpp41
-rw-r--r--source/gameengine/Ketsji/KX_EmptyObject.h47
-rw-r--r--source/gameengine/Ketsji/KX_GameActuator.cpp221
-rw-r--r--source/gameengine/Ketsji/KX_GameActuator.h88
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp1174
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.h630
-rw-r--r--source/gameengine/Ketsji/KX_IInterpolator.h47
-rw-r--r--source/gameengine/Ketsji/KX_IPOTransform.h89
-rw-r--r--source/gameengine/Ketsji/KX_IPO_SGController.cpp197
-rw-r--r--source/gameengine/Ketsji/KX_IPO_SGController.h107
-rw-r--r--source/gameengine/Ketsji/KX_IPhysicsController.cpp53
-rw-r--r--source/gameengine/Ketsji/KX_IPhysicsController.h103
-rw-r--r--source/gameengine/Ketsji/KX_IScalarInterpolator.h43
-rw-r--r--source/gameengine/Ketsji/KX_ISceneConverter.h81
-rw-r--r--source/gameengine/Ketsji/KX_ISystem.h56
-rw-r--r--source/gameengine/Ketsji/KX_IpoActuator.cpp720
-rw-r--r--source/gameengine/Ketsji/KX_IpoActuator.h158
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp1469
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.h344
-rw-r--r--source/gameengine/Ketsji/KX_Light.cpp263
-rw-r--r--source/gameengine/Ketsji/KX_Light.h57
-rw-r--r--source/gameengine/Ketsji/KX_LightIpoSGController.cpp125
-rw-r--r--source/gameengine/Ketsji/KX_LightIpoSGController.h101
-rw-r--r--source/gameengine/Ketsji/KX_MaterialIpoController.cpp98
-rw-r--r--source/gameengine/Ketsji/KX_MaterialIpoController.h54
-rw-r--r--source/gameengine/Ketsji/KX_MeshProxy.cpp233
-rw-r--r--source/gameengine/Ketsji/KX_MeshProxy.h71
-rw-r--r--source/gameengine/Ketsji/KX_MotionState.cpp97
-rw-r--r--source/gameengine/Ketsji/KX_MotionState.h55
-rw-r--r--source/gameengine/Ketsji/KX_MouseFocusSensor.cpp448
-rw-r--r--source/gameengine/Ketsji/KX_MouseFocusSensor.h162
-rw-r--r--source/gameengine/Ketsji/KX_NearSensor.cpp283
-rw-r--r--source/gameengine/Ketsji/KX_NearSensor.h87
-rw-r--r--source/gameengine/Ketsji/KX_ObColorIpoSGController.cpp116
-rw-r--r--source/gameengine/Ketsji/KX_ObColorIpoSGController.h76
-rw-r--r--source/gameengine/Ketsji/KX_ObjectActuator.cpp398
-rw-r--r--source/gameengine/Ketsji/KX_ObjectActuator.h141
-rw-r--r--source/gameengine/Ketsji/KX_OdePhysicsController.cpp251
-rw-r--r--source/gameengine/Ketsji/KX_OdePhysicsController.h102
-rw-r--r--source/gameengine/Ketsji/KX_OrientationInterpolator.cpp58
-rw-r--r--source/gameengine/Ketsji/KX_OrientationInterpolator.h59
-rw-r--r--source/gameengine/Ketsji/KX_PhysicsEngineEnums.h47
-rw-r--r--source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp167
-rw-r--r--source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h59
-rw-r--r--source/gameengine/Ketsji/KX_PhysicsPropertiesobsolete.h61
-rw-r--r--source/gameengine/Ketsji/KX_PolygonMaterial.cpp425
-rw-r--r--source/gameengine/Ketsji/KX_PolygonMaterial.h127
-rw-r--r--source/gameengine/Ketsji/KX_PositionInterpolator.cpp44
-rw-r--r--source/gameengine/Ketsji/KX_PositionInterpolator.h59
-rw-r--r--source/gameengine/Ketsji/KX_PyConstraintBinding.cpp553
-rw-r--r--source/gameengine/Ketsji/KX_PyConstraintBinding.h44
-rw-r--r--source/gameengine/Ketsji/KX_PyMath.cpp114
-rw-r--r--source/gameengine/Ketsji/KX_PyMath.h164
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.cpp1157
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.h61
-rw-r--r--source/gameengine/Ketsji/KX_RadarSensor.cpp259
-rw-r--r--source/gameengine/Ketsji/KX_RadarSensor.h96
-rw-r--r--source/gameengine/Ketsji/KX_RayCast.cpp101
-rw-r--r--source/gameengine/Ketsji/KX_RayCast.h107
-rw-r--r--source/gameengine/Ketsji/KX_RayEventManager.cpp60
-rw-r--r--source/gameengine/Ketsji/KX_RayEventManager.h55
-rw-r--r--source/gameengine/Ketsji/KX_RaySensor.cpp392
-rw-r--r--source/gameengine/Ketsji/KX_RaySensor.h85
-rw-r--r--source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp361
-rw-r--r--source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h130
-rw-r--r--source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp139
-rw-r--r--source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h78
-rw-r--r--source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp209
-rw-r--r--source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h89
-rw-r--r--source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp154
-rw-r--r--source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h109
-rw-r--r--source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp339
-rw-r--r--source/gameengine/Ketsji/KX_SG_NodeRelationships.h204
-rw-r--r--source/gameengine/Ketsji/KX_ScalarInterpolator.cpp41
-rw-r--r--source/gameengine/Ketsji/KX_ScalarInterpolator.h64
-rw-r--r--source/gameengine/Ketsji/KX_ScalingInterpolator.cpp44
-rw-r--r--source/gameengine/Ketsji/KX_ScalingInterpolator.h59
-rw-r--r--source/gameengine/Ketsji/KX_Scene.cpp1350
-rw-r--r--source/gameengine/Ketsji/KX_Scene.h557
-rw-r--r--source/gameengine/Ketsji/KX_SceneActuator.cpp359
-rw-r--r--source/gameengine/Ketsji/KX_SceneActuator.h116
-rw-r--r--source/gameengine/Ketsji/KX_SoundActuator.cpp497
-rw-r--r--source/gameengine/Ketsji/KX_SoundActuator.h109
-rw-r--r--source/gameengine/Ketsji/KX_SumoPhysicsController.cpp229
-rw-r--r--source/gameengine/Ketsji/KX_SumoPhysicsController.h112
-rw-r--r--source/gameengine/Ketsji/KX_TimeCategoryLogger.cpp145
-rw-r--r--source/gameengine/Ketsji/KX_TimeCategoryLogger.h134
-rw-r--r--source/gameengine/Ketsji/KX_TimeLogger.cpp121
-rw-r--r--source/gameengine/Ketsji/KX_TimeLogger.h107
-rw-r--r--source/gameengine/Ketsji/KX_TouchEventManager.cpp154
-rw-r--r--source/gameengine/Ketsji/KX_TouchEventManager.h80
-rw-r--r--source/gameengine/Ketsji/KX_TouchSensor.cpp397
-rw-r--r--source/gameengine/Ketsji/KX_TouchSensor.h125
-rw-r--r--source/gameengine/Ketsji/KX_TrackToActuator.cpp532
-rw-r--r--source/gameengine/Ketsji/KX_TrackToActuator.h93
-rw-r--r--source/gameengine/Ketsji/KX_VehicleWrapper.cpp367
-rw-r--r--source/gameengine/Ketsji/KX_VehicleWrapper.h58
-rw-r--r--source/gameengine/Ketsji/KX_VertexProxy.cpp440
-rw-r--r--source/gameengine/Ketsji/KX_VertexProxy.h79
-rw-r--r--source/gameengine/Ketsji/KX_VisibilityActuator.cpp162
-rw-r--r--source/gameengine/Ketsji/KX_VisibilityActuator.h78
-rw-r--r--source/gameengine/Ketsji/KX_WorldInfo.cpp41
-rw-r--r--source/gameengine/Ketsji/KX_WorldInfo.h68
-rw-r--r--source/gameengine/Ketsji/KX_WorldIpoController.cpp120
-rw-r--r--source/gameengine/Ketsji/KX_WorldIpoController.h99
-rw-r--r--source/gameengine/Ketsji/Makefile74
-rw-r--r--source/gameengine/Ketsji/SConscript34
-rw-r--r--source/gameengine/Makefile47
-rw-r--r--source/gameengine/Network/CMakeLists.txt40
-rw-r--r--source/gameengine/Network/LoopBackNetwork/CMakeLists.txt40
-rw-r--r--source/gameengine/Network/LoopBackNetwork/Makefile44
-rw-r--r--source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.cpp119
-rw-r--r--source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.h69
-rw-r--r--source/gameengine/Network/LoopBackNetwork/SConscript8
-rw-r--r--source/gameengine/Network/Makefile51
-rw-r--r--source/gameengine/Network/NG_NetworkDeviceInterface.h85
-rw-r--r--source/gameengine/Network/NG_NetworkMessage.cpp59
-rw-r--r--source/gameengine/Network/NG_NetworkMessage.h131
-rw-r--r--source/gameengine/Network/NG_NetworkObject.cpp50
-rw-r--r--source/gameengine/Network/NG_NetworkObject.h48
-rw-r--r--source/gameengine/Network/NG_NetworkScene.cpp275
-rw-r--r--source/gameengine/Network/NG_NetworkScene.h104
-rw-r--r--source/gameengine/Network/SConscript8
-rw-r--r--source/gameengine/Network/TerraplayNetwork/Makefile45
-rw-r--r--source/gameengine/Network/TerraplayNetwork/NG_TerraplayNetworkDeviceInterface.cpp196
-rw-r--r--source/gameengine/Network/TerraplayNetwork/NG_TerraplayNetworkDeviceInterface.h69
-rw-r--r--source/gameengine/Physics/BlOde/Makefile51
-rw-r--r--source/gameengine/Physics/BlOde/OdePhysicsController.cpp622
-rw-r--r--source/gameengine/Physics/BlOde/OdePhysicsController.h157
-rw-r--r--source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp278
-rw-r--r--source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h93
-rw-r--r--source/gameengine/Physics/BlOde/SConscript15
-rw-r--r--source/gameengine/Physics/Bullet/CMakeLists.txt39
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.cpp636
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.h248
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp1307
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h242
-rw-r--r--source/gameengine/Physics/Bullet/Makefile44
-rw-r--r--source/gameengine/Physics/Bullet/SConscript15
-rw-r--r--source/gameengine/Physics/Dummy/CMakeLists.txt38
-rw-r--r--source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp121
-rw-r--r--source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h96
-rw-r--r--source/gameengine/Physics/Dummy/Makefile48
-rw-r--r--source/gameengine/Physics/Dummy/SConscript8
-rw-r--r--source/gameengine/Physics/Makefile41
-rw-r--r--source/gameengine/Physics/Sumo/CMakeLists.txt49
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/Makefile37
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/include/SM_Callback.h10
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/include/SM_ClientObjectInfo.h16
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/include/SM_Debug.h26
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/include/SM_FhObject.h59
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/include/SM_MotionState.h80
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/include/SM_Object.h396
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/include/SM_Props.h61
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/include/SM_Scene.h175
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/sample/Makefile25
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/sample/particle.cpp709
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/sample/particle0.cpp695
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/src/Makefile14
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/src/SM_FhObject.cpp183
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/src/SM_MotionState.cpp103
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/src/SM_Object.cpp1301
-rw-r--r--source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp376
-rw-r--r--source/gameengine/Physics/Sumo/Makefile53
-rw-r--r--source/gameengine/Physics/Sumo/SConscript26
-rw-r--r--source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.cpp66
-rw-r--r--source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.h28
-rw-r--r--source/gameengine/Physics/Sumo/SumoPhysicsController.cpp493
-rw-r--r--source/gameengine/Physics/Sumo/SumoPhysicsController.h188
-rw-r--r--source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp257
-rw-r--r--source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h108
-rw-r--r--source/gameengine/Physics/Sumo/convert.txt35
-rw-r--r--source/gameengine/Physics/Sumo/include/interpolator.h27
-rw-r--r--source/gameengine/Physics/common/CMakeLists.txt39
-rw-r--r--source/gameengine/Physics/common/Makefile61
-rw-r--r--source/gameengine/Physics/common/PHY_DynamicTypes.h93
-rw-r--r--source/gameengine/Physics/common/PHY_IMotionState.cpp41
-rw-r--r--source/gameengine/Physics/common/PHY_IMotionState.h57
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsController.cpp42
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsController.h103
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsEnvironment.cpp49
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h117
-rw-r--r--source/gameengine/Physics/common/PHY_IVehicle.cpp7
-rw-r--r--source/gameengine/Physics/common/PHY_IVehicle.h57
-rw-r--r--source/gameengine/Physics/common/PHY_Pro.h61
-rw-r--r--source/gameengine/Physics/common/SConscript8
-rw-r--r--source/gameengine/PyDoc/BL_ActionActuator.py153
-rw-r--r--source/gameengine/PyDoc/GameKeys.py166
-rw-r--r--source/gameengine/PyDoc/GameLogic.py223
-rw-r--r--source/gameengine/PyDoc/KX_CDActuator.py32
-rw-r--r--source/gameengine/PyDoc/KX_Camera.py187
-rw-r--r--source/gameengine/PyDoc/KX_CameraActuator.py86
-rw-r--r--source/gameengine/PyDoc/KX_ConstraintActuator.py72
-rw-r--r--source/gameengine/PyDoc/KX_GameActuator.py22
-rw-r--r--source/gameengine/PyDoc/KX_GameObject.py158
-rw-r--r--source/gameengine/PyDoc/KX_IpoActuator.py92
-rw-r--r--source/gameengine/PyDoc/KX_Light.py45
-rw-r--r--source/gameengine/PyDoc/KX_MeshProxy.py110
-rw-r--r--source/gameengine/PyDoc/KX_MouseFocusSensor.py26
-rw-r--r--source/gameengine/PyDoc/KX_NearSensor.py9
-rw-r--r--source/gameengine/PyDoc/KX_NetworkMessageActuator.py36
-rw-r--r--source/gameengine/PyDoc/KX_NetworkMessageSensor.py43
-rw-r--r--source/gameengine/PyDoc/KX_ObjectActuator.py154
-rw-r--r--source/gameengine/PyDoc/KX_PolygonMaterial.py281
-rw-r--r--source/gameengine/PyDoc/KX_RadarSensor.py31
-rw-r--r--source/gameengine/PyDoc/KX_RaySensor.py33
-rw-r--r--source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py74
-rw-r--r--source/gameengine/PyDoc/KX_SCA_EndObjectActuator.py11
-rw-r--r--source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py73
-rw-r--r--source/gameengine/PyDoc/KX_Scene.py70
-rw-r--r--source/gameengine/PyDoc/KX_SceneActuator.py55
-rw-r--r--source/gameengine/PyDoc/KX_SoundActuator.py145
-rw-r--r--source/gameengine/PyDoc/KX_TouchSensor.py50
-rw-r--r--source/gameengine/PyDoc/KX_TrackToActuator.py57
-rw-r--r--source/gameengine/PyDoc/KX_VertexProxy.py122
-rw-r--r--source/gameengine/PyDoc/KX_VisibilityActuator.py17
-rw-r--r--source/gameengine/PyDoc/Makefile13
-rw-r--r--source/gameengine/PyDoc/Rasterizer.py147
-rw-r--r--source/gameengine/PyDoc/SCA_ANDController.py11
-rw-r--r--source/gameengine/PyDoc/SCA_AlwaysSensor.py9
-rw-r--r--source/gameengine/PyDoc/SCA_IActuator.py9
-rw-r--r--source/gameengine/PyDoc/SCA_IController.py9
-rw-r--r--source/gameengine/PyDoc/SCA_ILogicBrick.py32
-rw-r--r--source/gameengine/PyDoc/SCA_ISensor.py62
-rw-r--r--source/gameengine/PyDoc/SCA_KeyboardSensor.py58
-rw-r--r--source/gameengine/PyDoc/SCA_MouseSensor.py23
-rw-r--r--source/gameengine/PyDoc/SCA_ORController.py11
-rw-r--r--source/gameengine/PyDoc/SCA_PropertyActuator.py38
-rw-r--r--source/gameengine/PyDoc/SCA_PropertySensor.py57
-rw-r--r--source/gameengine/PyDoc/SCA_PythonController.py49
-rw-r--r--source/gameengine/PyDoc/SCA_RandomActuator.py143
-rw-r--r--source/gameengine/PyDoc/SCA_RandomSensor.py28
-rw-r--r--source/gameengine/PyDoc/WhatsNew.py34
-rw-r--r--source/gameengine/Rasterizer/CMakeLists.txt40
-rw-r--r--source/gameengine/Rasterizer/Makefile53
-rw-r--r--source/gameengine/Rasterizer/RAS_BucketManager.cpp197
-rw-r--r--source/gameengine/Rasterizer/RAS_BucketManager.h73
-rw-r--r--source/gameengine/Rasterizer/RAS_CameraData.h63
-rw-r--r--source/gameengine/Rasterizer/RAS_Deformer.h56
-rw-r--r--source/gameengine/Rasterizer/RAS_FramingManager.cpp234
-rw-r--r--source/gameengine/Rasterizer/RAS_FramingManager.h256
-rw-r--r--source/gameengine/Rasterizer/RAS_ICanvas.h174
-rw-r--r--source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp160
-rw-r--r--source/gameengine/Rasterizer/RAS_IPolygonMaterial.h166
-rw-r--r--source/gameengine/Rasterizer/RAS_IRasterizer.h411
-rw-r--r--source/gameengine/Rasterizer/RAS_IRenderTools.cpp78
-rw-r--r--source/gameengine/Rasterizer/RAS_IRenderTools.h202
-rw-r--r--source/gameengine/Rasterizer/RAS_LightObject.h67
-rw-r--r--source/gameengine/Rasterizer/RAS_MaterialBucket.cpp332
-rw-r--r--source/gameengine/Rasterizer/RAS_MaterialBucket.h169
-rw-r--r--source/gameengine/Rasterizer/RAS_MeshObject.cpp699
-rw-r--r--source/gameengine/Rasterizer/RAS_MeshObject.h267
-rw-r--r--source/gameengine/Rasterizer/RAS_ObjectColor.h42
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/ARB_multitexture.h150
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt40
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/EXT_separate_specular_color.h12
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile49
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp691
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h537
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp210
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h72
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp1995
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h318
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp352
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h78
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript9
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/glext.h6495
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/mkglext.py630
-rw-r--r--source/gameengine/Rasterizer/RAS_Polygon.cpp145
-rw-r--r--source/gameengine/Rasterizer/RAS_Polygon.h93
-rw-r--r--source/gameengine/Rasterizer/RAS_Rect.h98
-rw-r--r--source/gameengine/Rasterizer/RAS_TexMatrix.h43
-rw-r--r--source/gameengine/Rasterizer/RAS_TexVert.cpp180
-rw-r--r--source/gameengine/Rasterizer/RAS_TexVert.h135
-rw-r--r--source/gameengine/Rasterizer/RAS_texmatrix.cpp134
-rw-r--r--source/gameengine/Rasterizer/SConscript13
-rw-r--r--source/gameengine/SConscript27
-rw-r--r--source/gameengine/SceneGraph/CMakeLists.txt38
-rw-r--r--source/gameengine/SceneGraph/Makefile41
-rw-r--r--source/gameengine/SceneGraph/SConscript9
-rw-r--r--source/gameengine/SceneGraph/SG_BBox.cpp253
-rw-r--r--source/gameengine/SceneGraph/SG_BBox.h134
-rw-r--r--source/gameengine/SceneGraph/SG_Controller.cpp53
-rw-r--r--source/gameengine/SceneGraph/SG_Controller.h120
-rw-r--r--source/gameengine/SceneGraph/SG_IObject.cpp167
-rw-r--r--source/gameengine/SceneGraph/SG_IObject.h235
-rw-r--r--source/gameengine/SceneGraph/SG_Node.cpp239
-rw-r--r--source/gameengine/SceneGraph/SG_Node.h211
-rw-r--r--source/gameengine/SceneGraph/SG_ParentRelation.h117
-rw-r--r--source/gameengine/SceneGraph/SG_Spatial.cpp330
-rw-r--r--source/gameengine/SceneGraph/SG_Spatial.h229
-rw-r--r--source/gameengine/SceneGraph/SG_Tree.cpp414
-rw-r--r--source/gameengine/SceneGraph/SG_Tree.h156
-rw-r--r--source/icons/Makefile39
-rw-r--r--source/icons/SConscript6
-rw-r--r--source/icons/winblender.icobin0 -> 25214 bytes
-rw-r--r--source/icons/winblender.rc2
-rw-r--r--source/icons/winblender.rcscons2
-rw-r--r--source/icons/winblenderfile.icobin0 -> 25214 bytes
-rw-r--r--source/icons/wincreator.icobin0 -> 4710 bytes
-rw-r--r--source/icons/wincreator.rc2
-rw-r--r--source/icons/winlockedfile.icobin0 -> 4710 bytes
-rw-r--r--source/icons/winplayer.icobin0 -> 4710 bytes
-rw-r--r--source/icons/winplayer.rc1
-rw-r--r--source/icons/winpublisher.icobin0 -> 4710 bytes
-rw-r--r--source/icons/winpublisher.rc3
-rw-r--r--source/kernel/CMakeLists.txt41
-rw-r--r--source/kernel/Makefile40
-rw-r--r--source/kernel/SConscript10
-rw-r--r--source/kernel/gen_messaging/GEN_messaging.h61
-rw-r--r--source/kernel/gen_messaging/Makefile37
-rw-r--r--source/kernel/gen_messaging/intern/Makefile43
-rw-r--r--source/kernel/gen_messaging/intern/messaging.c48
-rw-r--r--source/kernel/gen_system/GEN_DataCache.h79
-rw-r--r--source/kernel/gen_system/GEN_HashedPtr.cpp61
-rw-r--r--source/kernel/gen_system/GEN_HashedPtr.h48
-rw-r--r--source/kernel/gen_system/GEN_Map.h150
-rw-r--r--source/kernel/gen_system/GEN_Matrix4x4.cpp209
-rw-r--r--source/kernel/gen_system/GEN_Matrix4x4.h79
-rw-r--r--source/kernel/gen_system/GEN_SmartPtr.h236
-rw-r--r--source/kernel/gen_system/Makefile43
-rw-r--r--source/kernel/gen_system/SYS_SingletonSystem.cpp103
-rw-r--r--source/kernel/gen_system/SYS_SingletonSystem.h66
-rw-r--r--source/kernel/gen_system/SYS_System.cpp81
-rw-r--r--source/kernel/gen_system/SYS_System.h71
-rw-r--r--source/nan_compile.mk391
-rw-r--r--source/nan_definitions.mk603
-rw-r--r--source/nan_link.mk164
-rw-r--r--source/nan_subdirs.mk79
-rw-r--r--source/nan_warn.mk169
1681 files changed, 712354 insertions, 0 deletions
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
new file mode 100644
index 00000000000..9da00ddfc0d
--- /dev/null
+++ b/source/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 *****
+
+SUBDIRS(blender kernel)
+
+IF(WITH_GAMEENGINE)
+ SUBDIRS(gameengine)
+ENDIF(WITH_GAMEENGINE)
+
+IF(WINDOWS)
+ SUBDIRS(icons)
+ENDIF(WINDOWS)
diff --git a/source/Makefile b/source/Makefile
new file mode 100644
index 00000000000..5161f6b73c5
--- /dev/null
+++ b/source/Makefile
@@ -0,0 +1,648 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Top level makefile. Start looping through subdirs and link....
+#
+
+ifndef NANENV
+ export NANENV := $(shell env | grep NAN_)
+endif
+
+include nan_definitions.mk
+
+DIRS = creator blender kernel
+
+ifneq ($(NAN_NO_KETSJI),true)
+ DIRS += gameengine
+endif
+
+ifeq ($(OS),windows)
+ DIRS += icons
+endif
+
+########## buildinfo kludge ###################
+CPPFLAGS += -I../Physics/common
+CPPFLAGS += -I../Physics/Dummy
+ifdef NAN_BUILDINFO
+ BUILDINFO_O = $(DIR)/$(DEBUG_DIR)buildinfo.o
+ BUILDINFO_C = $(SRCHOME)/creator/buildinfo.c
+ BUILD_DATE := $(shell date "+%Y-%m-%d")
+ BUILD_TIME := $(shell date "+%H:%M:%S")
+endif
+
+############# set pyplayerlib ##################
+
+PYPLAYERLIB ?= $(PYLIB)
+
+############# libraries ##################
+# COMLIB COMmon LIBraries for all targets
+# BPLIB Browser Plugin LIBraries
+# SPLIB1 Standalone Player LIBraries (pre COMLIB)
+# SPLIB Standalone Player LIBraries (post COMLIB)
+# PULIB PUblisher LIBraries
+# GRPLIB Gui and Render LIBraries for Publisher
+# LLIBS dynamic system libraries
+# SADD Static OpenGL libraries
+# DADD Dynamic OpenGL libraries
+# NSPLUGLIB PLUGin LIBraries for ns-style api
+# PLUGAPPLIB libs that form the application to be plugged in
+# Note: the order is important here
+
+GRPLIB = $(OCGDIR)/creator/$(DEBUG_DIR)libcreator.a
+GRPLIB += $(OCGDIR)/blender/src/$(DEBUG_DIR)libsrcpublisher.a
+GRPLIB += $(NAN_BSP)/lib/$(DEBUG_DIR)libbsp.a
+GRPLIB += $(NAN_BOOLOP)/lib/$(DEBUG_DIR)libboolop.a
+GRPLIB += $(NAN_SOUNDSYSTEM)/lib/$(DEBUG_DIR)libSoundSystem.a
+GRPLIB += $(NAN_GHOST)/lib/$(DEBUG_DIR)libghost.a
+GRPLIB += $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a
+GRPLIB += $(OCGDIR)/blender/render/$(DEBUG_DIR)librender.a
+GRPLIB += $(OCGDIR)/blender/radiosity/$(DEBUG_DIR)libradiosity.a
+GRPLIB += $(NAN_OPENNL)/lib/$(DEBUG_DIR)libopennl.a
+GRPLIB += $(NAN_SUPERLU)/lib/$(DEBUG_DIR)libsuperlu.a
+GRPLIB += $(OCGDIR)/blender/python/$(DEBUG_DIR)libpython.a
+
+# nlin: the reason that some libraries appear more than once below is
+# to handle circular dependencies in linking among libraries... some
+# linkers (e.g. under Linux) need libs to be specified multiple times
+# to properly resolve circular dependencies. ugly, but it works...
+# the repeat entries could probably be trimmed down.
+COMLIB = $(OCGDIR)/blender/blenkernel/$(DEBUG_DIR)libblenkernel.a
+COMLIB += $(NAN_DECIMATION)/lib/libdecimation.a
+COMLIB += $(OCGDIR)/blender/blenloader/$(DEBUG_DIR)libblenloader.a
+COMLIB += $(OCGDIR)/blender/blenpluginapi/$(DEBUG_DIR)libblenpluginapi.a
+COMLIB += $(OCGDIR)/blender/nodes_shd/$(DEBUG_DIR)libnodes_shd.a
+COMLIB += $(OCGDIR)/blender/nodes_cmp/$(DEBUG_DIR)libnodes_cmp.a
+COMLIB += $(OCGDIR)/blender/nodes/$(DEBUG_DIR)libnodes.a
+COMLIB += $(OCGDIR)/blender/imbuf/$(DEBUG_DIR)libimbuf.a
+COMLIB += $(OCGDIR)/blender/blenlib/$(DEBUG_DIR)libblenlib.a
+COMLIB += $(OCGDIR)/blender/avi/$(DEBUG_DIR)libavi.a
+COMLIB += $(NAN_JPEG)/lib/libjpeg.a
+
+ifneq ($(NAN_NO_KETSJI),true)
+ COMLIB += $(OCGDIR)/gameengine/bloutines/$(DEBUG_DIR)libbloutines.a
+ COMLIB += $(OCGDIR)/gameengine/blconverter/$(DEBUG_DIR)libblconverter.a
+ COMLIB += $(OCGDIR)/gameengine/blphys/common/$(DEBUG_DIR)libcommon.a
+ COMLIB += $(OCGDIR)/gameengine/ketsji/$(DEBUG_DIR)libketsji.a
+ COMLIB += $(OCGDIR)/gameengine/blconverter/$(DEBUG_DIR)libblconverter.a
+ COMLIB += $(OCGDIR)/gameengine/blconverter/$(DEBUG_DIR)libblconverter.a
+ COMLIB += $(NAN_SOLID)/lib/libsolid.a
+ COMLIB += $(NAN_SOLID)/lib/libsolid_broad.a
+ COMLIB += $(NAN_SOLID)/lib/libsolid_complex.a
+ COMLIB += $(NAN_SOLID)/lib/libsolid_convex.a
+ COMLIB += $(OCGDIR)/gameengine/blphys/sumo/$(DEBUG_DIR)libsumo.a
+ COMLIB += $(OCGDIR)/gameengine/blphys/fuzzics/$(DEBUG_DIR)libfuzzics.a
+ COMLIB += $(NAN_QHULL)/lib/libqhull.a
+ COMLIB += $(OCGDIR)/gameengine/blphys/dummy/$(DEBUG_DIR)libdummy.a
+ COMLIB += $(OCGDIR)/gameengine/blphys/common/$(DEBUG_DIR)libcommon.a
+# COMLIB += $(OCGDIR)/gameengine/blphys/sumo/$(DEBUG_DIR)libsumo.a
+ COMLIB += $(OCGDIR)/gameengine/blphys/dummy/$(DEBUG_DIR)libdummy.a
+ COMLIB += $(OCGDIR)/gameengine/ketsji/$(DEBUG_DIR)libketsji.a
+ COMLIB += $(OCGDIR)/gameengine/blphys/common/$(DEBUG_DIR)libcommon.a
+# COMLIB += $(OCGDIR)/gameengine/blphys/blode/$(DEBUG_DIR)libblode.a
+# COMLIB += $(OCGDIR)/gameengine/blphys/sumo/$(DEBUG_DIR)libsumo.a
+ COMLIB += $(OCGDIR)/gameengine/blphys/dummy/$(DEBUG_DIR)libdummy.a
+ COMLIB += $(OCGDIR)/gameengine/blphys/blbullet/$(DEBUG_DIR)libblbullet.a
+ COMLIB += $(OCGDIR)/gameengine/blphys/common/$(DEBUG_DIR)libcommon.a
+# COMLIB += $(OCGDIR)/gameengine/blphys/sumo/$(DEBUG_DIR)libsumo.a
+ COMLIB += $(OCGDIR)/gameengine/blphys/dummy/$(DEBUG_DIR)libdummy.a
+ COMLIB += $(OCGDIR)/gameengine/ketsji/$(DEBUG_DIR)libketsji.a
+ COMLIB += $(OCGDIR)/gameengine/logic/$(DEBUG_DIR)liblogic.a
+ COMLIB += $(OCGDIR)/gameengine/logic/Joystick/$(DEBUG_DIR)libJoystick.a
+ COMLIB += $(OCGDIR)/gameengine/rasterizer/$(DEBUG_DIR)librasterizer.a
+ COMLIB += $(OCGDIR)/gameengine/OpenGLrasterizer/$(DEBUG_DIR)libOpenGLrasterizer.a
+ COMLIB += $(OCGDIR)/gameengine/expression/$(DEBUG_DIR)libexpression.a
+ COMLIB += $(OCGDIR)/gameengine/scenegraph/$(DEBUG_DIR)libscenegraph.a
+# COMLIB += $(OCGDIR)/sumo/$(DEBUG_DIR)libfuzzics.a
+# COMLIB += $(OCGDIR)/sumo/$(DEBUG_DIR)libsolid.a
+ COMLIB += $(NAN_MOTO)/lib/libmoto.a
+ COMLIB += $(NAN_SND_LIBS)
+ COMLIB += $(OCGDIR)/kernel/gen_system/$(DEBUG_DIR)libgen_system.a
+ COMLIB += $(OCGDIR)/kernel/gen_messaging/$(DEBUG_DIR)libgen_messaging.a
+ COMLIB += $(OCGDIR)/gameengine/ketsji/KXNetwork/$(DEBUG_DIR)libKXNetwork.a
+ COMLIB += $(OCGDIR)/gameengine/Network/$(DEBUG_DIR)libNetwork.a
+ COMLIB += $(OCGDIR)/gameengine/Network/LoopBackNetwork/$(DEBUG_DIR)libLoopBackNetwork.a
+ COMLIB += $(NAN_BULLET2)/lib/libbullet2.a
+endif
+
+COMLIB += $(NAN_GUARDEDALLOC)/lib/libguardedalloc.a
+COMLIB += $(NAN_MEMUTIL)/lib/libmemutil.a
+COMLIB += $(NAN_BMFONT)/lib/$(DEBUG_DIR)libbmfont.a
+COMLIB += $(NAN_PNG)/lib/libpng.a
+COMLIB += $(OCGDIR)/blender/yafray/$(DEBUG_DIR)libyafrayexport.a
+COMLIB += $(OCGDIR)/blender/blenlib/$(DEBUG_DIR)libblenlib.a
+
+ifeq ($(WITH_QUICKTIME), true)
+ COMLIB += $(OCGDIR)/blender/blenderqt/$(DEBUG_DIR)libblenderqt.a
+endif
+
+ifeq ($(WITH_OPENEXR), true)
+ COMLIB += $(OCGDIR)/blender/imbuf/openexr/$(DEBUG_DIR)libopenexr.a
+endif
+
+COMLIB += $(OCGDIR)/blender/imbuf/cineon/$(DEBUG_DIR)libcineon.a
+
+ifeq ($(WITH_DDS), true)
+ COMLIB += $(OCGDIR)/blender/imbuf/dds/$(DEBUG_DIR)libdds.a
+endif
+
+ifeq ($(WITH_FREETYPE2), true)
+ ifeq ($(OS), windows)
+ ifeq ($(FREE_WINDOWS), true)
+ COMLIB += $(NAN_FREETYPE)/lib/libfreetype.a
+ else
+ COMLIB += $(NAN_FREETYPE)/lib/freetype2ST.lib
+ endif
+ else
+ ifeq ($(OS), irix)
+ COMLIB += $(NAN_FREETYPE)/lib32/libfreetype.a
+ else
+ COMLIB += $(NAN_FREETYPE)/lib/libfreetype.a
+ endif
+ endif
+endif
+
+ifeq ($(INTERNATIONAL), true)
+ COMLIB += $(OCGDIR)/blender/ftfont/$(DEBUG_DIR)libftfont.a
+ ifeq ($(OS), windows)
+ ifeq ($(FREE_WINDOWS), true)
+ COMLIB += $(NAN_GETTEXT)/lib/freegettext.a
+ COMLIB += $(NAN_FTGL)/lib/libftgl.a
+ #COMLIB += $(NAN_ICONV)/lib/freeiconv.a
+ else
+ COMLIB += $(NAN_GETTEXT)/lib/gnu_gettext.lib
+ COMLIB += $(NAN_FTGL)/lib/ftgl_static_ST.lib
+ COMLIB += $(NAN_FREETYPE)/lib/freetype2ST.lib
+ COMLIB += $(NAN_ICONV)/lib/iconv.lib
+ endif
+ else
+ COMLIB += $(NAN_FTGL)/lib/libftgl.a
+ ifeq ($(OS), irix)
+ COMLIB += $(NAN_FREETYPE)/lib32/libfreetype.a
+ COMLIB += $(NAN_FREETYPE)/lib32/libintl.a
+ else
+ COMLIB += $(NAN_FREETYPE)/lib/libfreetype.a
+ endif
+ endif
+ ifeq ($(OS), darwin)
+ COMLIB += $(NAN_GETTEXT)/lib/libintl.a
+ ifeq ($(CPU), i386)
+ COMLIB += $(NAN_GETTEXT)/lib/libiconv.a
+ endif
+ endif
+ ifeq ($(OS), solaris)
+ COMLIB += $(NAN_GETTEXT)/lib/libintl.a
+ endif
+endif
+
+ifeq ($(WITH_VERSE), true)
+ ifeq ($(OS), windows)
+ ifeq ($(FREE_WINDOWS), true)
+ COMLIB += $(NAN_VERSE)/lib/libverse.a
+ else
+ COMLIB += $(NAN_VERSE)/lib/verse.lib
+ endif
+ else
+ COMLIB += $(NAN_VERSE)/lib/libverse.a
+ endif
+endif
+
+ifeq ($(OS), irix)
+ COMLIB += $(NAN_SDL)/lib/libSDL.a
+endif
+
+ifeq ($(OS), windows)
+ ifeq ($(FREE_WINDOWS), true)
+ COMLIB += $(NAN_SDL)/lib/libSDL.a
+ COMLIB += $(NAN_PTHREADS)/lib/libpthreadGC2.a
+ else
+ COMLIB += $(NAN_SDL)/lib/SDL.lib
+ endif
+endif
+
+ifeq ($(WITH_OPENEXR), true)
+ COMLIB += $(NAN_OPENEXR_LIBS)
+endif
+
+PULIB = $(NAN_IKSOLVER)/lib/libiksolver.a
+PULIB += $(NAN_MOTO)/lib/libmoto.a
+PULIB += $(NAN_ELBEEM)/lib/$(DEBUG_DIR)libelbeem.a
+PULIB += $(OCGDIR)/blender/readblenfile/$(DEBUG_DIR)libreadblenfile.a
+PULIB += $(OCGDIR)/blender/src/$(DEBUG_DIR)libsrcpublisher.a
+
+ifeq ($(NAN_NO_KETSJI),true)
+ PULIB += $(NAN_MOTO)/lib/libmoto.a
+ PULIB += $(OCGDIR)/kernel/gen_system/$(DEBUG_DIR)libgen_system.a
+ PULIB += $(OCGDIR)/kernel/gen_messaging/$(DEBUG_DIR)libgen_messaging.a
+ COMLIB += $(NAN_SND_LIBS)
+endif
+
+SPLIB1 = $(OCGDIR)/gameengine/GamePlayer/ghost/$(DEBUG_DIR)libghost.a
+SPLIB1 += $(OCGDIR)/gameengine/GamePlayer/common/$(DEBUG_DIR)libcommon.a
+SPLIB1 += $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a
+SPLIB1 += $(NAN_GHOST)/lib/$(DEBUG_DIR)libghost.a
+
+SPLIB = $(OCGDIR)/blender/makesdna/$(DEBUG_DIR)DNA.o
+SPLIB += $(OCGDIR)/blender/readblenfile/$(DEBUG_DIR)libreadblenfile.a
+# this is used for the plugin. It uses some things from libz.a,
+# but somehow it consistently fails to resolve these symbols... or
+# can I just not check them? nm claims they aren't...
+SPLIB += $(OCGDIR)/blender/blenkernel/blenkernel_blc/$(DEBUG_DIR)libblenkernel_blc.a
+
+# These three need to be explicitly mentioned on the cl, because
+# if they are offered as a lib, they are optimized away. (nzc)
+NSPLUGLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)UnixShell.o
+NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)stubs.o
+NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)winstubs.o
+NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)Blender3DPlugin_native_implementation.o
+
+# Here you can configure what sort of test to make for the plugin.
+# PLUGTESTLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/test/$(DEBUG_DIR)libns_api_test_stub.a
+# PLUGTESTLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/test/$(DEBUG_DIR)libns_api_test_colorcycle.a
+# PLUGTESTLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/test/$(DEBUG_DIR)libns_api_test_gears.a
+PLUGTESTLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/test/$(DEBUG_DIR)libns_api_test_threaded_gears.a
+
+# XPCOM is done only for Linux for now
+ifeq ($(OS),$(findstring $(OS), "linux"))
+ ifeq ($(CPU),i386)
+ NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)XPH_xpcom_hooks.o
+ endif
+endif
+
+PLUGAPPLIB = $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)libplugin_ketsji_hooks.a
+
+ifeq ($(OS),$(findstring $(OS), "freebsd linux irix solaris"))
+ NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)PLG_X11_windowing.o
+ PLUGAPPLIB += $(OCGDIR)/gameengine/GamePlayer/common/unix/$(DEBUG_DIR)libunix.a
+endif
+ifeq ($(OS),$(findstring $(OS), "windows"))
+ NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)PLG_MSWindows_windowing.o
+ NSPLUGLIB += $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)npB3DPlg.res
+ PLUGAPPLIB += $(OCGDIR)/gameengine/GamePlayer/common/windows/$(DEBUG_DIR)libwindows.a
+endif
+
+PLUGAPPLIB += $(OCGDIR)/gameengine/GamePlayer/common/$(DEBUG_DIR)libcommon.a
+
+ifeq ($(OS),$(findstring $(OS), "linux"))
+ ifeq ($(CPU),i386)
+ PLUGAPPLIB_XPLINK = $(OCGDIR)/gameengine/GamePlayer/netscape/src/$(DEBUG_DIR)_Blender3DPlugin_implementation_.o
+ endif
+endif
+
+# A bit silly... but needed to resolve symbols.
+PLUGREMLIB = $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a
+
+######################## OS dependencies (alphabetic!) ################
+
+include nan_link.mk
+
+ifeq ($(NAN_JUST_BLENDERDYNAMIC),true)
+ BINTARGETS = blenderdynamic
+endif
+
+ifeq ($(WITH_BF_DYNAMICOPENGL), true)
+ BINTARGETS += blenderdynamic
+endif
+
+ifeq ($(WITH_BF_STATICOPENGL), true)
+ BINTARGETS += blenderstatic
+endif
+
+ifeq ($(WITH_BF_BLENDERPLAYER), true)
+ export WITH_BF_GAMEENGINE=true
+ BINTARGETS += blenderplayer
+endif
+
+ifeq ($(WITH_BF_WEBPLUGIN), true)
+ ifneq ($(NAN_NO_PLUGIN), true)
+ BINTARGETS += plugin
+ ifeq ($(OS),linux)
+ ifeq ($(CPU),i386)
+ BINTARGETS += xplink
+ endif
+ endif
+ endif
+endif
+
+ifdef PY_FRAMEWORK
+ PYLIB = -framework Python
+else
+ PYLIB = $(NAN_PYTHON)/lib/python$(NAN_PYTHON_VERSION)/config/libpython$(NAN_PYTHON_VERSION).a
+endif
+
+ifeq ($(OS),solaris)
+ PYLIB += $(NAN_ZLIB)/lib/libz.a
+ PULIB += $(NAN_ZLIB)/lib/libz.a
+ SPLIB += $(NAN_ZLIB)/lib/libz.a
+endif
+
+# OpenAL libs are already compiled as shared code! Check FMod if we switch to that. (nzc)
+
+# Some vars to keep the rest of this section mostly readable
+# in an 80 char term
+SOUNDSYSTEM = $(OCGDIR)/intern/SoundSystem/$(DEBUG_DIR)libSoundSystem.a
+DUMMYSOUND = $(OCGDIR)/intern/DummySoundSystem/$(DEBUG_DIR)libDummySoundSystem.a
+OPENALSOUND = $(OCGDIR)/intern/OpenALSoundSystem/$(DEBUG_DIR)libOpenALSoundSystem.a
+SDLSOUND = $(OCGDIR)/intern/SDLSoundSystem/$(DEBUG_DIR)libSDLSoundSystem.a
+
+# Some kooky logic going on here ...
+ifeq ($(NAN_NO_OPENAL), true)
+ NAN_SND_LIBS = $(SOUNDSYSTEM)
+ NAN_SND_LIBS += $(DUMMYSOUND)
+ NAN_SND_LIBS += $(SOUNDSYSTEM)
+else
+ ifeq ($(OS),$(findstring $(OS), "freebsd linux windows"))
+ ifeq ($(CPU),$(findstring $(CPU), "i386 powerpc x86_64"))
+ NAN_SND_LIBS = $(SOUNDSYSTEM)
+ NAN_SND_LIBS += $(DUMMYSOUND)
+ NAN_SND_LIBS += $(OPENALSOUND)
+ NAN_SND_LIBS += $(SDLSOUND)
+ NAN_SND_LIBS += $(NAN_OPENAL)/lib/libopenal.a
+ ALUT = $(wildcard $(NAN_OPENAL)/lib/libalut.a)
+ NAN_SND_LIBS += $(ALUT)
+ NAN_SND_LIBS += $(SOUNDSYSTEM)
+ else
+ ifeq ($(OS),windows)
+ NAN_SND_LIBS = $(SOUNDSYSTEM)
+ NAN_SND_LIBS += $(DUMMYSOUND)
+ NAN_SND_LIBS += $(OPENALSOUND)
+ NAN_SND_LIBS += $(SDLSOUND)
+ NAN_SND_LIBS += $(NAN_OPENAL)/lib/openal_static.lib
+ ALUT = $(wildcard $(NAN_OPENAL)/lib/alut_static.lib)
+ NAN_SND_LIBS += $(ALUT)
+ NAN_SND_LIBS += $(SOUNDSYSTEM)
+ else
+ NAN_SND_LIBS = $(SOUNDSYSTEM)
+ NAN_SND_LIBS += $(DUMMYSOUND)
+ NAN_SND_LIBS += $(SOUNDSYSTEM)
+ endif
+ endif
+ else
+ ifeq ($(OS),darwin)
+ NAN_SND_LIBS = $(SOUNDSYSTEM)
+ NAN_SND_LIBS += $(DUMMYSOUND)
+ NAN_SND_LIBS += $(OPENALSOUND)
+ NAN_SND_LIBS += $(NAN_OPENAL)/lib/libopenal.a
+ ALUT = $(wildcard $(NAN_OPENAL)/lib/libalut.a)
+ NAN_SND_LIBS += $(ALUT)
+ NAN_SND_LIBS += $(SOUNDSYSTEM)
+ else
+ ifeq ($(OS), solaris)
+ NAN_SND_LIBS = $(SOUNDSYSTEM)
+ NAN_SND_LIBS += $(DUMMYSOUND)
+ NAN_SND_LIBS += $(OPENALSOUND)
+ NAN_SND_LIBS += $(SDLSOUND)
+ NAN_SND_LIBS += $(NAN_OPENAL)/lib/libopenal.a
+ ALUT = $(wildcard $(NAN_OPENAL)/lib/libalut.a)
+ NAN_SND_LIBS += $(ALUT)
+ NAN_SND_LIBS += $(SOUNDSYSTEM)
+ else
+ NAN_SND_LIBS = $(SOUNDSYSTEM)
+ NAN_SND_LIBS += $(DUMMYSOUND)
+ NAN_SND_LIBS += $(SOUNDSYSTEM)
+ endif
+ endif
+ endif
+endif
+
+ifeq ($(OS),windows)
+ ifeq ($(FREE_WINDOWS),true)
+ PYLIB = $(NAN_PYTHON)/lib/freepy.a
+ else
+ PYLIB = $(NAN_PYTHON)/lib/python23.lib
+ endif
+
+ PYPLAYERLIB = $(NAN_PYTHON)/static/*.obj
+ PYPLAYERLIB = $(PYLIB)
+
+ # Might need to change this to $(NAN_MOZILLA_LIB)/nspr4.lib
+ NSPLUGLIB += $(NAN_NSPR)/lib/nspr4.lib
+
+ BINTARGETS = blenderdynamic
+ ifeq ($(FREE_WINDOWS),true)
+ ifneq ($(NAN_NO_KETSJI),true)
+ BINTARGETS += blenderplayer
+ endif
+ else
+ BINTARGETS += blenderplayer
+ BINTARGETS += blenderdynplayer
+ BINTARGETS += plugin
+ endif
+
+ PULIB += $(OCGDIR)/blender/icons/$(DEBUG_DIR)winblender.res
+ PULIB += $(NAN_ZLIB)/lib/libz.a
+ SPLIB += $(OCGDIR)/blender/icons/$(DEBUG_DIR)winblender.res
+ SPLIB += $(NAN_ZLIB)/lib/libz.a
+endif
+
+
+# prepare for NAN_BUILDINFO compile at the *sigh* link rules below
+
+ifdef NAN_BUILDINFO
+ CSRCS =
+ ALLTARGETS =
+ include nan_compile.mk
+endif
+
+################## target rules ########################
+
+all debug ::
+ @echo "****> Make $@ by $(ID)@$(HOST) at $(MAKE_START) on $(CONFIG_GUESS)"
+ifdef NANENV
+ @for n in $(NANENV); do \
+ echo " $$n"; \
+ done
+endif
+
+DIR = $(OCGDIR)
+SOURCEDIR = source
+
+include nan_subdirs.mk
+
+################## target rules ########################
+
+all:: link
+
+debug debuglink::
+ @$(MAKE) link DEBUG_DIR="debug/" NANENV=$(NANENV)
+
+clean:: linkclean debuglinkclean
+
+link: $(BINTARGETS)
+ @echo "****> Build $(MAKE_START) - `date '+%H:%M:%S %d-%b-%Y'`"
+ifdef NANENV
+ @for n in $(NANENV); do \
+ echo " $$n"; \
+ done
+endif
+
+linkclean:
+ @$(RM) -r $(DIR)/blenderstatic* \
+ $(DIR)/blenderplayer* \
+ $(DIR)/bin/*
+
+debuglinkclean:
+ @$(RM) -r $(DIR)/debug/blenderstatic* \
+ $(DIR)/debug/blenderplayer* \
+ $(DIR)/debug/bin/*
+
+# Shortcut for Tinderbox release builds. Mortals don't use this.
+release:
+ @$(MAKE) -C ../release/ all || exit 1;
+
+############### Linker rules ###############
+
+blenderstatic: $(DIR)/$(DEBUG_DIR)bin/blenderstatic
+blenderdynamic: $(DIR)/$(DEBUG_DIR)bin/blender$(EXT)
+blenderplayer: $(DIR)/$(DEBUG_DIR)bin/blenderplayer$(EXT)
+blenderdynplayer: $(DIR)/$(DEBUG_DIR)bin/blenderdynplayer$(EXT)
+
+# XPCOM connector only for linux so far...
+ifeq ($(OS),linux)
+ xplink: $(DIR)/$(DEBUG_DIR)bin/Blender3DPlugin$(SOEXT)
+endif
+
+# Moz/NS plugin:
+ifeq ($(OS),$(findstring $(OS), "freebsd linux irix solaris"))
+ plugin: $(DIR)/$(DEBUG_DIR)bin/npBlender3DPlugin$(SOEXT)
+ ptest: $(DIR)/$(DEBUG_DIR)bin/npTestPlugin$(SOEXT)
+endif
+# Windows needs a 8.3 name... Why? Dunno...
+ifeq ($(OS),windows)
+ ifneq ($(FREE_WINDOWS),true)
+ plugin: $(DIR)/$(DEBUG_DIR)npB3DPlg$(SOEXT)
+ endif
+endif
+
+$(DIR)/$(DEBUG_DIR)bin/blenderstatic: $(OBJS) $(GRPLIB) $(COMLIB) $(PULIB)
+ @echo "****> Link $@"
+ifdef NAN_BUILDINFO
+ $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"static"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO
+endif
+ mkdir -p $(DIR)/$(DEBUG_DIR)bin
+ $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blenderstatic $(BUILDINFO_O) $(OBJS) $(GRPLIB) $(COMLIB) $(PULIB) $(PYLIB) $(LLIBS) $(SADD) $(LOPTS)
+ifdef NAN_BUILDINFO
+ /bin/rm $(BUILDINFO_O)
+endif
+ifeq ($(OS), darwin)
+ @$(MAKE) -C darwin/ APPLICATION=blenderstatic
+endif
+
+$(DIR)/$(DEBUG_DIR)bin/blender$(EXT): $(OBJS) $(GRPLIB) $(COMLIB) $(PULIB)
+ @echo "****> Link $@"
+ifdef NAN_BUILDINFO
+ $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO
+endif
+ mkdir -p $(DIR)/$(DEBUG_DIR)bin
+ $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blender$(EXT) $(BUILDINFO_O) $(OBJS) $(GRPLIB) $(COMLIB) $(PULIB) $(PYLIB) $(LLIBS) $(DADD) $(LOPTS)
+ifdef NAN_BUILDINFO
+ /bin/rm $(BUILDINFO_O)
+endif
+ifeq ($(OS), darwin)
+ @$(MAKE) -C darwin/ APPLICATION=blender
+endif
+
+$(DIR)/$(DEBUG_DIR)bin/blenderplayer$(EXT): $(OBJS) $(SPLIB1) $(COMLIB) $(SPLIB)
+ @echo "****> Link $@"
+ifdef NAN_BUILDINFO
+ $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO
+endif
+ mkdir -p $(DIR)/$(DEBUG_DIR)bin
+ $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blenderplayer$(EXT) $(BUILDINFO_O) $(OBJS) $(SPLIB1) $(COMLIB) $(SPLIB) $(PYPLAYERLIB) $(LLIBS) $(DADD) $(LOPTS)
+ifdef NAN_BUILDINFO
+ /bin/rm $(BUILDINFO_O)
+endif
+ifeq ($(OS), darwin)
+ @$(MAKE) -C darwin/ APPLICATION=blenderplayer
+endif
+
+$(DIR)/$(DEBUG_DIR)bin/blenderdynplayer$(EXT): $(OBJS) $(COMLIB) $(SPLIB)
+ @echo "****> Link $@"
+ifdef NAN_BUILDINFO
+ $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO
+endif
+ mkdir -p $(DIR)/$(DEBUG_DIR)bin
+ $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blenderdynplayer$(EXT) $(BUILDINFO_O) $(OBJS) $(SPLIB1) $(COMLIB) $(SPLIB) $(PYLIB) $(LLIBS) $(DADD) $(LOPTS)
+ifdef NAN_BUILDINFO
+ /bin/rm $(BUILDINFO_O)
+endif
+ifeq ($(OS), darwin)
+ @$(MAKE) -C darwin/ APPLICATION=blenderplayer
+endif
+
+$(DIR)/$(DEBUG_DIR)bin/Blender3DPlugin$(SOEXT): $(PLUGAPPLIB_XPLINK)
+ @echo "****> Link $@"
+ifdef NAN_BUILDINFO
+ $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO
+endif
+ mkdir -p $(DIR)/$(DEBUG_DIR)bin
+ $(CCC) $(DYNLDFLAGS) -o $@ $(PLUGAPPLIB_XPLINK) $(LOPTS)
+ifdef NAN_BUILDINFO
+ /bin/rm $(BUILDINFO_O)
+endif
+
+# Windows build needs a def file? Why? For exposing functions from the
+# dll to the outside world. However, this is alsi done internally..
+DEFFILE = ./gameengine/GamePlayer/netscape/src/npB3DPlg.def
+
+# Windows needs a specific name format for dll.s so we give it one.
+$(DIR)/$(DEBUG_DIR)npB3DPlg$(SOEXT): $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB)
+ @echo "****> Link $@"
+ifdef NAN_BUILDINFO
+ $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO
+endif
+# $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) $(PYLIB) $(PLUGREMLIB) $(LLIBS) $(DADD) $(LOPTS)
+ $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) $(PYLIB) $(PLUGREMLIB) $(LLIBS) $(DADD) $(LOPTS) /def:$(DEFFILE)
+ifdef NAN_BUILDINFO
+ /bin/rm $(BUILDINFO_O)
+endif
+
+$(DIR)/$(DEBUG_DIR)bin/npBlender3DPlugin$(SOEXT): $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB)
+ @echo "****> Link $@"
+ifdef NAN_BUILDINFO
+ $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO
+endif
+ mkdir -p $(DIR)/$(DEBUG_DIR)bin
+ $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) $(PYLIB) $(PLUGREMLIB) $(LLIBS) $(DADD) $(LOPTS)
+ifdef NAN_BUILDINFO
+ /bin/rm $(BUILDINFO_O)
+endif
+
+$(DIR)/$(DEBUG_DIR)bin/npTestPlugin$(SOEXT): $(NSPLUGLIB)
+ @echo "****> Link $@"
+ifdef NAN_BUILDINFO
+ $(CCC) $(REL_CFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO
+endif
+ mkdir -p $(DIR)/$(DEBUG_DIR)bin
+ $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGTESTLIB) $(LLIBS) $(DADD) $(LOPTS)
+ifdef NAN_BUILDINFO
+ /bin/rm $(BUILDINFO_O)
+endif
+
diff --git a/source/SConscript b/source/SConscript
new file mode 100644
index 00000000000..ca264579f6e
--- /dev/null
+++ b/source/SConscript
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+Import ('env')
+
+SConscript(['blender/SConscript',
+ 'kernel/SConscript',
+ 'creator/SConscript'])
+if env['WITH_BF_GAMEENGINE'] == 1:
+ SConscript (['gameengine/SConscript'])
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
+ SConscript (['icons/SConscript'])
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 */
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
new file mode 100644
index 00000000000..a34ed069b02
--- /dev/null
+++ b/source/creator/CMakeLists.txt
@@ -0,0 +1,276 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if 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 *****
+
+SETUP_LIBDIRS()
+
+INCLUDE_DIRECTORIES(../../intern/guardedalloc
+ ../blender/blenlib
+ ../blender/blenkernel
+ ../blender/nodes
+ ../blender/include
+ ../blender/blenloader
+ ../blender/imbuf
+ ../blender/renderconverter
+ ../blender/render/extern/include
+ ../blender/python
+ ../blender/makesdna
+ ../kernel/gen_messaging
+ ../kernel/gen_system
+)
+
+IF(WITH_QUICKTIME)
+ ADD_DEFINITIONS(-DWITH_QUICKTIME)
+ENDIF(WITH_QUICKTIME)
+
+IF(YESIAMSTUPID)
+ ADD_DEFINITIONS(-DYESIAMSTUPID)
+ENDIF(YESIAMSTUPID)
+
+MESSAGE(STATUS "Configuring blender")
+
+ADD_CUSTOM_COMMAND(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dna.c
+ COMMAND ${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/makesdna ${CMAKE_CURRENT_BINARY_DIR}/dna.c ${CMAKE_SOURCE_DIR}/source/blender/makesdna/
+ DEPENDS ${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/makesdna
+)
+
+IF(WIN32)
+ ADD_EXECUTABLE(blender ${EXETYPE} creator.c ${CMAKE_CURRENT_BINARY_DIR}/dna.c ../icons/winblender.rc)
+ELSE(WIN32)
+ ADD_EXECUTABLE(blender ${EXETYPE} creator.c ${CMAKE_CURRENT_BINARY_DIR}/dna.c)
+ENDIF(WIN32)
+
+
+# Post build steps for bundling/packaging.
+
+SET(TARGETDIR ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR})
+
+
+IF(UNIX)
+ ADD_CUSTOM_COMMAND(TARGET blender
+ POST_BUILD
+ MAIN_DEPENDENCY blender
+ #COMMAND cp -R ${CMAKE_SOURCE_DIR}/release/plugins ${TARGETDIR}/
+ #COMMAND cp -R ${CMAKE_SOURCE_DIR}/release/text/* ${TARGETDIR}/
+ )
+ENDIF(UNIX)
+
+IF(UNIX AND NOT APPLE)
+ ADD_CUSTOM_COMMAND(TARGET blender
+ POST_BUILD
+ MAIN_DEPENDENCY blender
+ COMMAND rm -Rf ${TARGETDIR}/.blender
+ COMMAND mkdir ${TARGETDIR}/.blender/
+ COMMAND cp ${CMAKE_SOURCE_DIR}/bin/.blender/.bfont.ttf ${TARGETDIR}/.blender/
+ COMMAND cp ${CMAKE_SOURCE_DIR}/bin/.blender/.Blanguages ${TARGETDIR}/.blender/
+ COMMAND cp -R ${CMAKE_SOURCE_DIR}/bin/.blender/locale ${TARGETDIR}/.blender/
+ COMMAND cp -R ${CMAKE_SOURCE_DIR}/release/scripts ${TARGETDIR}/.blender/
+ COMMAND find ${TARGETDIR} -name CVS -prune -exec rm -rf {} "\;"
+ )
+ENDIF(UNIX AND NOT APPLE)
+
+IF(APPLE)
+ SET(SOURCEDIR ${CMAKE_SOURCE_DIR}/source/darwin/blender.app)
+ SET(SOURCEINFO ${SOURCEDIR}/Contents/Info.plist)
+ SET(TARGETINFO ${TARGETDIR}/blender.app/Contents/Info.plist)
+
+ ADD_CUSTOM_COMMAND(TARGET blender
+ POST_BUILD
+ MAIN_DEPENDENCY blender
+ COMMAND cp -R ${SOURCEINFO} ${TARGETDIR}/blender.app/Contents/
+ COMMAND cp -R ${SOURCEDIR}/Contents/PkgInfo ${TARGETDIR}/blender.app/Contents/
+ COMMAND cp -R ${SOURCEDIR}/Contents/Resources ${TARGETDIR}/blender.app/Contents/
+ COMMAND cat ${SOURCEINFO} | sed s/VERSION/`cat ${CMAKE_SOURCE_DIR}/release/VERSION`/ | sed s/DATE/`date +'%Y-%b-%d'`/ > ${TARGETINFO}
+ COMMAND rm -Rf ${TARGETDIR}/blender.app/Contents/MacOS/.blender
+ COMMAND mkdir ${TARGETDIR}/blender.app/Contents/MacOS/.blender/
+ COMMAND cp ${CMAKE_SOURCE_DIR}/bin/.blender/.bfont.ttf ${TARGETDIR}/blender.app/Contents/MacOS/.blender/
+ COMMAND cp ${CMAKE_SOURCE_DIR}/bin/.blender/.Blanguages ${TARGETDIR}/blender.app/Contents/MacOS/.blender/
+ COMMAND cp -R ${CMAKE_SOURCE_DIR}/bin/.blender/locale ${TARGETDIR}/blender.app/Contents/Resources/
+ COMMAND cp -R ${CMAKE_SOURCE_DIR}/bin/.blender/locale ${TARGETDIR}/blender.app/Contents/MacOS/.blender/
+ COMMAND cp ${CMAKE_SOURCE_DIR}/bin/.blender/.Blanguages ${TARGETDIR}/blender.app/Contents/Resources/
+ COMMAND cp -R ${CMAKE_SOURCE_DIR}/release/scripts ${TARGETDIR}/blender.app/Contents/MacOS/.blender/
+ COMMAND find ${TARGETDIR}/blender.app -name CVS -prune -exec rm -rf {} "\;"
+ COMMAND find ${TARGETDIR}/blender.app -name CVS.sandboxinfo -prune -exec rm -rf {} "\;"
+ COMMAND find ${TARGETDIR}/blender.app -name .DS_Store -prune -exec rm -rf {} "\;"
+ )
+ENDIF(APPLE)
+
+IF(WIN32)
+ FILE(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} WIN_SOURCE_DIR)
+
+ ADD_CUSTOM_COMMAND(TARGET blender
+ POST_BUILD
+ MAIN_DEPENDENCY blender
+ COMMAND if not exist \"$\(TargetDir\)\\.blender\" mkdir \"$\(TargetDir\)\\.blender\"
+ COMMAND if not exist \"$\(TargetDir\)\\.blender\\locale\" mkdir \"$\(TargetDir\)\\.blender\\locale\"
+ COMMAND if not exist \"$\(TargetDir\)\\.blender\\scripts\" mkdir \"$\(TargetDir\)\\.blender\\scripts\"
+ COMMAND if not exist \"$\(TargetDir\)\\plugins\" mkdir \"$\(TargetDir\)\\plugins\"
+ COMMAND copy /Y \"${WIN_SOURCE_DIR}\\bin\\.blender\\.Blanguages\" \"$\(TargetDir\)\\.blender\\\"
+ COMMAND copy /Y \"${WIN_SOURCE_DIR}\\bin\\.blender\\.bfont.ttf\" \"$\(TargetDir\)\\.blender\\\"
+ COMMAND xcopy /E /Y \"${WIN_SOURCE_DIR}\\bin\\.blender\\locale\\*.*\" \"$\(TargetDir\)\\.blender\\locale\"
+ COMMAND xcopy /E /Y \"${WIN_SOURCE_DIR}\\release\\scripts\\*.*\" \"$\(TargetDir\)\\.blender\\scripts\"
+ COMMAND xcopy /E /Y \"${WIN_SOURCE_DIR}\\release\\plugins\\*.*\" \"$\(TargetDir\)\\plugins\"
+ COMMAND copy /Y \"${WIN_SOURCE_DIR}\\release\\text\\*.*\" \"$\(TargetDir\)\"
+ )
+
+ FILE(TO_NATIVE_PATH "${LIBDIR}" WIN_LIBDIR)
+
+ ADD_CUSTOM_COMMAND(TARGET blender
+ POST_BUILD
+ MAIN_DEPENDENCY blender
+ COMMAND copy /Y \"${WIN_LIBDIR}\\gettext\\lib\\gnu_gettext.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\png\\lib\\libpng.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\sdl\\lib\\SDL.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\zlib\\lib\\zlib.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\tiff\\lib\\libtiff.dll\" \"$\(TargetDir\)\\\"
+ COMMAND if $\(ConfigurationName\)==Debug copy /Y \"${WIN_LIBDIR}\\python\\lib\\python25_D.dll\" \"$\(TargetDir\)\\\"
+ COMMAND if $\(ConfigurationName\)==Debug copy /Y \"${WIN_LIBDIR}\\CRTL\\lib\\msvcrtd.dll\" \"$\(TargetDir\)\\\"
+ COMMAND if NOT $\(ConfigurationName\)==Debug copy /Y \"${WIN_LIBDIR}\\python\\lib\\python25.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\pthreads\\lib\\pthreadVC2.dll\" \"$\(TargetDir\)\\\"
+ )
+
+ IF(WITH_INTERNATIONAL)
+ ADD_CUSTOM_COMMAND(TARGET blender
+ POST_BUILD
+ MAIN_DEPENDENCY blender
+ COMMAND copy /Y \"${WIN_LIBDIR}\\iconv\\lib\\iconv.dll\" \"$\(TargetDir\)\\\"
+ )
+ ENDIF(WITH_INTERNATIONAL)
+
+ IF(WITH_FFMPEG)
+ ADD_CUSTOM_COMMAND(TARGET blender
+ POST_BUILD
+ MAIN_DEPENDENCY blender
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\avcodec-51.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\avformat-51.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\avutil-49.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\libdts.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\libfaac.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\libfaad.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\libgsm.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\libmp3lame-0.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\libogg-0.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\libvorbis-0.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\libvorbisenc-2.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\libx264-54.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\postproc-51.dll\" \"$\(TargetDir\)\\\"
+ COMMAND copy /Y \"${WIN_LIBDIR}\\ffmpeg\\lib\\xvidcore.dll\" \"$\(TargetDir\)\\\"
+ )
+ ENDIF(WITH_FFMPEG)
+ENDIF(WIN32)
+
+ADD_DEPENDENCIES(blender makesdna)
+
+FILE(READ ${CMAKE_BINARY_DIR}/cmake_blender_libs.txt BLENDER_LINK_LIBS)
+
+SET(BLENDER_LINK_LIBS bf_nodes ${BLENDER_LINK_LIBS} src blender_python blender_render blender_radiosity blender_IK bf_elbeem)
+
+IF(UNIX)
+ # Sort libraries
+ SET(BLENDER_SORTED_LIBS
+ src
+ bf_decimation
+ blender_BSP
+ bf_soundsystem
+ bf_ghost
+ bf_string
+ blender_render
+ blender_radiosity
+ blender_ONL
+ blender_python
+ bf_blenkernel
+ bf_nodes
+ bf_blenloader
+ bf_blenpluginapi
+ bf_imbuf
+ bf_blenlib
+ bf_avi
+ bf_cineon
+ bf_openexr
+ bf_readblenfile
+ blender_bop
+ bf_kernel
+ bf_decimation
+ bf_elbeem
+ bf_yafray
+ blender_IK
+ bf_memutil
+ bf_guardedalloc
+ blender_CTR
+ bf_moto
+ bf_bmfont
+ verse
+ src
+ bf_ftfont
+ extern_ftgl
+ bf_blroutines
+ bf_converter
+ bf_dummy
+ bf_bullet
+ bf_common
+ bf_ketsji
+ bf_logic
+ bf_rasterizer
+ bf_oglrasterizer
+ bf_expressions
+ bf_scenegraph
+ bf_moto
+ bf_blroutines
+ kx_network
+ bf_kernel
+ bf_ngnetwork
+ extern_bullet
+ bf_loopbacknetwork
+ bf_sumo
+ bf_common
+ extern_solid
+ extern_qhull
+ bf_moto
+ blender_python
+ bf_quicktime
+ )
+
+ FOREACH(SORTLIB ${BLENDER_SORTED_LIBS})
+ SET(REMLIB ${SORTLIB})
+ FOREACH(SEARCHLIB ${BLENDER_LINK_LIBS})
+ IF(${SEARCHLIB} STREQUAL ${SORTLIB})
+ SET(REMLIB "")
+ ENDIF(${SEARCHLIB} STREQUAL ${SORTLIB})
+ ENDFOREACH(SEARCHLIB)
+ IF(REMLIB)
+ MESSAGE(STATUS "Removing library ${REMLIB} from blender linking because: not configured")
+ LIST(REMOVE_ITEM BLENDER_SORTED_LIBS ${REMLIB})
+ ENDIF(REMLIB)
+ ENDFOREACH(SORTLIB)
+ TARGET_LINK_LIBRARIES(blender ${BLENDER_SORTED_LIBS})
+ELSE(UNIX)
+ TARGET_LINK_LIBRARIES(blender ${BLENDER_LINK_LIBS})
+ENDIF(UNIX)
+
+SETUP_LIBLINKS(blender)
diff --git a/source/creator/Makefile b/source/creator/Makefile
new file mode 100644
index 00000000000..02c22aa4da8
--- /dev/null
+++ b/source/creator/Makefile
@@ -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 *****
+#
+
+LIBNAME = creator
+DIR = $(OCGDIR)/creator
+
+# this HAS to go
+CSRCS = creator.c
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I../blender/render/extern/include
+CPPFLAGS += -I../blender/radiosity/extern/include
+# two needed for the kernel
+CPPFLAGS += -I../blender/imbuf
+CPPFLAGS += -I../blender/makesdna
+CPPFLAGS += -I../blender/blenlib
+CPPFLAGS += -I../blender/include
+CPPFLAGS += -I../blender/renderconverter
+CPPFLAGS += -I../blender/blenkernel
+CPPFLAGS += -I../blender/python
+CPPFLAGS += -I../blender/blenloader
+CPPFLAGS += -I../kernel/gen_system
+CPPFLAGS += -I../kernel/gen_messaging
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+
+ifeq ($(WITH_QUICKTIME), true)
+ CPPFLAGS += -I$(NAN_QUICKTIME)/include -DWITH_QUICKTIME
+endif
+
+ifeq ($(NAN_YESIAMSTUPID), true)
+ CPPFLAGS += -DYESIAMSTUPID
+endif
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
diff --git a/source/creator/SConscript b/source/creator/SConscript
new file mode 100644
index 00000000000..9bc49b2fc30
--- /dev/null
+++ b/source/creator/SConscript
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = 'creator.c'
+
+incs = '#/intern/guardedalloc ../blender/blenlib ../blender/blenkernel'
+incs += ' ../blender/include ../blender/blenloader ../blender/imbuf'
+incs += ' ../blender/renderconverter ../blender/render/extern/include'
+incs += ' ../blender/python ../blender/makesdna ../kernel/gen_messaging'
+incs += ' ../kernel/gen_system'
+incs += ' ' + env['BF_OPENGL_INC']
+
+defs = []
+if env['WITH_BF_QUICKTIME']==1:
+ incs += ' ' + env['BF_QUICKTIME_INC']
+ defs.append('WITH_QUICKTIME')
+
+env.BlenderLib ( libname = 'blender_creator', sources = Split(sources), includes = Split(incs), defines = defs, libtype='core', priority = 1 )
diff --git a/source/creator/buildinfo.c b/source/creator/buildinfo.c
new file mode 100644
index 00000000000..feda7484f79
--- /dev/null
+++ b/source/creator/buildinfo.c
@@ -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 *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef BUILD_DATE
+#ifndef WIN32
+char * build_date=BUILD_DATE;
+char * build_time=BUILD_TIME;
+char * build_platform=BUILD_PLATFORM;
+char * build_type=BUILD_TYPE;
+#else
+#include "winbuildinfo.h"
+#endif
+#endif
diff --git a/source/creator/creator.c b/source/creator/creator.c
new file mode 100644
index 00000000000..8983582e44a
--- /dev/null
+++ b/source/creator/creator.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 <stdlib.h>
+#include <string.h>
+
+/* This little block needed for linking to Blender... */
+
+#include "MEM_guardedalloc.h"
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include "GEN_messaging.h"
+
+#include "DNA_ID.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "blendef.h" /* for MAXFRAME */
+
+
+#include "BKE_utildefines.h"
+#include "BKE_blender.h"
+#include "BKE_font.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_packedFile.h"
+#include "BKE_scene.h"
+#include "BKE_node.h"
+
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_mainqueue.h"
+#include "BIF_graphics.h"
+#include "BIF_editsound.h"
+#include "BIF_usiblender.h"
+#include "BIF_drawscene.h" /* set_scene() */
+#include "BIF_screen.h" /* waitcursor and more */
+#include "BIF_usiblender.h"
+#include "BIF_toolbox.h"
+
+#include "BLO_writefile.h"
+#include "BLO_readfile.h"
+
+#include "BDR_drawmesh.h"
+
+#include "IMB_imbuf.h" // for quicktime_init
+
+#include "BPY_extern.h"
+
+#include "RE_pipeline.h"
+
+#include "playanim_ext.h"
+#include "mydevice.h"
+#include "nla.h"
+#include "datatoc.h"
+
+/* for passing information between creator and gameengine */
+#include "SYS_System.h"
+
+#include <signal.h>
+
+#ifdef __FreeBSD__
+# include <sys/types.h>
+# include <floatingpoint.h>
+# include <sys/rtprio.h>
+#endif
+
+// from buildinfo.c
+#ifdef BUILD_DATE
+extern char * build_date;
+extern char * build_time;
+extern char * build_platform;
+extern char * build_type;
+#endif
+
+/* Local Function prototypes */
+static void print_help();
+static void print_version();
+
+
+/* defined in ghostwinlay and winlay, we can't include carbon here, conflict with DNA */
+#ifdef __APPLE__
+extern int checkAppleVideoCard(void);
+extern void getMacAvailableBounds(short *top, short *left, short *bottom, short *right);
+extern void winlay_get_screensize(int *width_r, int *height_r);
+extern void winlay_process_events(int wait_for_event);
+#endif
+
+
+/* for the callbacks: */
+
+extern int pluginapi_force_ref(void); /* from blenpluginapi:pluginapi.c */
+
+char bprogname[FILE_MAXDIR+FILE_MAXFILE]; /* from blenpluginapi:pluginapi.c */
+
+
+/* Initialise callbacks for the modules that need them */
+void setCallbacks(void);
+
+#if defined(__sgi) || defined(__alpha__)
+static void fpe_handler(int sig)
+{
+ // printf("SIGFPE trapped\n");
+}
+#endif
+
+/* handling ctrl-c event in console */
+static void blender_esc(int sig)
+{
+ static int count = 0;
+
+ G.afbreek = 1; /* forces render loop to read queue, not sure if its needed */
+
+ if (sig == 2) {
+ if (count) {
+ printf("\nBlender killed\n");
+ exit(2);
+ }
+ printf("\nSent an internal break event. Press ^C again to kill Blender\n");
+ count++;
+ }
+}
+
+static void print_version(void)
+{
+#ifdef BUILD_DATE
+ printf ("Blender %d.%02d (sub %d) Build\n", G.version/100, G.version%100, BLENDER_SUBVERSION);
+ printf ("\tbuild date: %s\n", build_date);
+ printf ("\tbuild time: %s\n", build_time);
+ printf ("\tbuild platform: %s\n", build_platform);
+ printf ("\tbuild type: %s\n", build_type);
+#else
+ printf ("Blender %d.%02d (sub %d) Build\n", G.version/100, G.version%100, BLENDER_SUBVERSION);
+#endif
+}
+
+static void print_help(void)
+{
+ printf ("Blender %d.%02d (sub %d) Build\n", G.version/100, G.version%100, BLENDER_SUBVERSION);
+ printf ("Usage: blender [options ...] [file]\n");
+
+ printf ("\nRender options:\n");
+ printf (" -b <file>\tRender <file> in background\n");
+ printf (" -S <name>\tSet scene <name>\n");
+ printf (" -f <frame>\tRender frame <frame> and save it\n");
+ printf (" -s <frame>\tSet start to frame <frame> (use with -a)\n");
+ printf (" -e <frame>\tSet end to frame (use with -a)<frame>\n");
+ printf (" -o <path>\tSet the render path and file name.\n");
+ printf (" Use // at the start of the path to\n");
+ printf (" render relative to the blend file.\n");
+ printf (" The frame number will be added at the end of the filename.\n");
+ printf (" eg: blender -b foobar.blend -o //render_ -F PNG -x 1\n");
+ printf (" -F <format>\tSet the render format, Valid options are..\n");
+ printf (" \tTGA IRIS HAMX FTYPE JPEG MOVIE IRIZ RAWTGA\n");
+ printf (" \tAVIRAW AVIJPEG PNG BMP FRAMESERVER\n");
+ printf (" (formats that can be compiled into blender, not available on all systems)\n");
+ printf (" \tHDR TIFF EXR MPEG AVICODEC QUICKTIME CINEON DPX\n");
+ printf (" -x <bool>\tSet option to add the file extension to the end of the file.\n");
+ printf (" -t <threads>\tUse amount of <threads> for rendering\n");
+ printf ("\nAnimation options:\n");
+ printf (" -a <file(s)>\tPlayback <file(s)>\n");
+ printf (" -p <sx> <sy>\tOpen with lower left corner at <sx>, <sy>\n");
+ printf (" -m\t\tRead from disk (Don't buffer)\n");
+
+ printf ("\nWindow options:\n");
+ printf (" -w\t\tForce opening with borders (default)\n");
+ printf (" -W\t\tForce opening without borders\n");
+ printf (" -p <sx> <sy> <w> <h>\tOpen with lower left corner at <sx>, <sy>\n");
+ printf (" \tand width and height <w>, <h>\n");
+ printf ("\nGame Engine specific options:\n");
+ printf (" -g fixedtime\t\tRun on 50 hertz without dropping frames\n");
+ printf (" -g vertexarrays\tUse Vertex Arrays for rendering (usually faster)\n");
+ printf (" -g noaudio\t\tNo audio in Game Engine\n");
+ printf (" -g nomipmap\t\tNo Texture Mipmapping\n");
+ printf (" -g linearmipmap\tLinear Texture Mipmapping instead of Nearest (default)\n");
+
+ printf ("\nMisc options:\n");
+ printf (" -d\t\tTurn debugging on\n");
+ printf (" -noaudio\tDisable audio on systems that support audio\n");
+ printf (" -h\t\tPrint this help text\n");
+ printf (" -y\t\tDisable script links, use -Y to find out why its -y\n");
+ printf (" -P <filename>\tRun the given Python script (filename or Blender Text)\n");
+#ifdef WIN32
+ printf (" -R\t\tRegister .blend extension\n");
+#endif
+ printf (" -v\t\tPrint Blender version and exit\n");
+ printf (" --\t\tEnds option processing. Following arguments are \n");
+ printf (" \t\t passed unchanged. Access via Python's sys.argv\n");
+}
+
+
+double PIL_check_seconds_timer(void);
+extern void winlay_get_screensize(int *width_r, int *height_r);
+
+int main(int argc, char **argv)
+{
+ int a, i, stax, stay, sizx, sizy;
+ SYS_SystemHandle syshandle;
+ Scene *sce;
+
+#if defined(WIN32) || defined (__linux__)
+ int audio = 1;
+#else
+ int audio = 0;
+#endif
+
+ setCallbacks();
+#ifdef __APPLE__
+ /* patch to ignore argument finder gives us (pid?) */
+ if (argc==2 && strncmp(argv[1], "-psn_", 5)==0) {
+ extern int GHOST_HACK_getFirstFile(char buf[]);
+ static char firstfilebuf[512];
+ int scr_x,scr_y;
+
+ argc= 1;
+
+ /* first let us check if we are hardware accelerated and with VRAM > 16 Mo */
+
+ if (checkAppleVideoCard()) {
+ short top, left, bottom, right;
+
+ winlay_get_screensize(&scr_x, &scr_y);
+ getMacAvailableBounds(&top, &left, &bottom, &right);
+ setprefsize(left +10,scr_y - bottom +10,right-left -20,bottom - 64, 0);
+
+ } else {
+ winlay_get_screensize(&scr_x, &scr_y);
+
+ /* 40 + 684 + (headers) 22 + 22 = 768, the powerbook screen height */
+ setprefsize(120, 40, 850, 684, 0);
+ }
+
+ winlay_process_events(0);
+ if (GHOST_HACK_getFirstFile(firstfilebuf)) {
+ argc= 2;
+ argv[1]= firstfilebuf;
+ }
+ }
+
+#endif
+
+#ifdef __FreeBSD__
+ fpsetmask(0);
+#endif
+#ifdef __linux__
+ #ifdef __alpha__
+ signal (SIGFPE, fpe_handler);
+ #else
+ if ( getenv("SDL_AUDIODRIVER") == NULL) {
+ setenv("SDL_AUDIODRIVER", "dma", 1);
+ }
+ #endif
+#endif
+#if defined(__sgi)
+ signal (SIGFPE, fpe_handler);
+#endif
+
+ // copy path to executable in bprogname. playanim and creting runtimes
+ // need this.
+
+ BLI_where_am_i(bprogname, argv[0]);
+
+ /* Hack - force inclusion of the plugin api functions,
+ * see blenpluginapi:pluginapi.c
+ */
+ pluginapi_force_ref();
+
+ init_nodesystem();
+
+ initglobals(); /* blender.c */
+
+ syshandle = SYS_GetSystem();
+ GEN_init_messaging_system();
+
+ /* first test for background */
+
+ G.f |= G_DOSCRIPTLINKS; /* script links enabled by default */
+
+ for(a=1; a<argc; a++) {
+
+ /* Handle unix and windows style help requests */
+ if ((!strcmp(argv[a], "--help")) || (!strcmp(argv[a], "/?"))){
+ print_help();
+ exit(0);
+ }
+
+ /* end argument processing after -- */
+ if (!strcmp( argv[a], "--")){
+ a = argc;
+ break;
+ }
+
+ /* Handle long version request */
+ if (!strcmp(argv[a], "--version")){
+ print_version();
+ exit(0);
+ }
+
+ /* Handle -* switches */
+ else if(argv[a][0] == '-') {
+ switch(argv[a][1]) {
+ case 'a':
+ playanim(argc-1, argv+1);
+ exit(0);
+ break;
+ case 'b':
+ case 'B':
+ G.background = 1;
+ a= argc;
+ break;
+
+ case 'y':
+ G.f &= ~G_DOSCRIPTLINKS;
+ break;
+
+ case 'Y':
+ printf ("-y was used to disable script links because,\n");
+ printf ("\t-p being taken, Ton was of the opinion that Y\n");
+ printf ("\tlooked like a split (disabled) snake, and also\n");
+ printf ("\twas similar to a python's tongue (unproven).\n\n");
+
+ printf ("\tZr agreed because it gave him a reason to add a\n");
+ printf ("\tcompletely useless text into Blender.\n\n");
+
+ printf ("\tADDENDUM! Ton, in defense, found this picture of\n");
+ printf ("\tan Australian python, exhibiting her (his/its) forked\n");
+ printf ("\tY tongue. It could be part of an H Zr retorted!\n\n");
+ printf ("\thttp://www.users.bigpond.com/snake.man/\n");
+
+ exit(252);
+
+ case 'h':
+ print_help();
+ exit(0);
+ case 'v':
+ print_version();
+ exit(0);
+ default:
+ break;
+ }
+ }
+ }
+
+#ifdef __sgi
+ setuid(getuid()); /* end superuser */
+#endif
+
+ /* for all platforms, even windos has it! */
+ if(G.background) signal(SIGINT, blender_esc); /* ctrl c out bg render */
+
+ /* background render uses this font too */
+ BKE_font_register_builtin(datatoc_Bfont, datatoc_Bfont_size);
+
+ init_def_material();
+
+ if(G.background==0) {
+ for(a=1; a<argc; a++) {
+ if(argv[a][0] == '-') {
+ switch(argv[a][1]) {
+ case 'p': /* prefsize */
+ if (argc-a < 5) {
+ printf ("-p requires four arguments\n");
+ exit(1);
+ }
+ a++;
+ stax= atoi(argv[a]);
+ a++;
+ stay= atoi(argv[a]);
+ a++;
+ sizx= atoi(argv[a]);
+ a++;
+ sizy= atoi(argv[a]);
+
+ setprefsize(stax, stay, sizx, sizy, 0);
+ break;
+ case 'd':
+ G.f |= G_DEBUG; /* std output printf's */
+ printf ("Blender %d.%02d (sub %d) Build\n", G.version/100, G.version%100, BLENDER_SUBVERSION);
+ MEM_set_memory_debug();
+#ifdef NAN_BUILDINFO
+ printf("Build: %s %s %s %s\n", build_date, build_time, build_platform, build_type);
+
+#endif // NAN_BUILDINFO
+ for (i = 0; i < argc; i++) {
+ printf("argv[%d] = %s\n", i, argv[i]);
+ }
+ break;
+
+ case 'w':
+ /* XXX, fixme zr, with borders */
+ /* there probably is a better way to do
+ * this, right now do as if blender was
+ * called with "-p 0 0 xres yres" -- sgefant
+ */
+ winlay_get_screensize(&sizx, &sizy);
+ setprefsize(0, 0, sizx, sizy, 1);
+ G.windowstate = G_WINDOWSTATE_BORDER;
+ break;
+ case 'W':
+ /* XXX, fixme zr, borderless on win32 */
+ /* now on all platforms as of 20070411 - DJC */
+ G.windowstate = G_WINDOWSTATE_FULLSCREEN;
+ break;
+ case 'R':
+ /* Registering filetypes only makes sense on windows... */
+#ifdef WIN32
+ RegisterBlendExtension(argv[0]);
+#endif
+ break;
+ case 'n':
+ case 'N':
+ if (BLI_strcasecmp(argv[a], "-noaudio") == 0|| BLI_strcasecmp(argv[a], "-nosound") == 0) {
+ /**
+ notify the gameengine that no audio is wanted, even if the user didn't give
+ the flag -g noaudio.
+ */
+
+ SYS_WriteCommandLineInt(syshandle,"noaudio",1);
+ audio = 0;
+ if (G.f & G_DEBUG) printf("setting audio to: %d\n", audio);
+ }
+ break;
+ }
+ }
+ }
+
+ BPY_start_python(argc, argv);
+
+ /**
+ * NOTE: sound_init_audio() *must be* after start_python,
+ * at least on FreeBSD.
+ * added note (ton): i removed it altogether
+ */
+
+ BIF_init();
+
+ }
+ else {
+ BPY_start_python(argc, argv);
+
+ // (ton) Commented out. I have no idea whats thisfor... will mail around!
+ // SYS_WriteCommandLineInt(syshandle,"noaudio",1);
+ // audio = 0;
+ // sound_init_audio();
+ // if (G.f & G_DEBUG) printf("setting audio to: %d\n", audio);
+ }
+
+ /**
+ * NOTE: the U.pythondir string is NULL until BIF_init() is executed,
+ * so we provide the BPY_ function below to append the user defined
+ * pythondir to Python's sys.path at this point. Simply putting
+ * BIF_init() before BPY_start_python() crashes Blender at startup.
+ * Update: now this function also inits the bpymenus, which also depend
+ * on U.pythondir.
+ */
+ BPY_post_start_python();
+
+#ifdef WITH_QUICKTIME
+
+ quicktime_init();
+
+#endif /* WITH_QUICKTIME */
+
+ /* dynamically load libtiff, if available */
+ libtiff_init();
+ if (!G.have_libtiff && (G.f & G_DEBUG)) {
+ printf("Unable to load: libtiff.\n");
+ printf("Try setting the BF_TIFF_LIB environment variable if you want this support.\n");
+ printf("Example: setenv BF_TIFF_LIB /usr/lib/libtiff.so\n");
+ }
+
+ /* OK we are ready for it */
+
+ for(a=1; a<argc; a++) {
+ if (G.afbreek==1) break;
+
+ if(argv[a][0] == '-') {
+ switch(argv[a][1]) {
+ case '-': /* -- ends argument processing */
+ a = argc;
+ break;
+
+ case 'p': /* prefsize */
+ a+= 4;
+ break;
+
+ case 'g':
+ {
+ /**
+ gameengine parameters are automaticly put into system
+ -g [paramname = value]
+ -g [boolparamname]
+ example:
+ -g novertexarrays
+ -g maxvertexarraysize = 512
+ */
+
+ if(++a < argc)
+ {
+ char* paramname = argv[a];
+ /* check for single value versus assignment */
+ if (a+1 < argc && (*(argv[a+1]) == '='))
+ {
+ a++;
+ if (a+1 < argc)
+ {
+ a++;
+ /* assignment */
+ SYS_WriteCommandLineString(syshandle,paramname,argv[a]);
+ } else
+ {
+ printf("error: argument assignment (%s) without value.\n",paramname);
+ }
+ /* name arg eaten */
+
+ } else
+ {
+ SYS_WriteCommandLineInt(syshandle,argv[a],1);
+
+ /* doMipMap */
+ if (!strcmp(argv[a],"nomipmap"))
+ {
+ set_mipmap(0); //doMipMap = 0;
+ }
+ /* linearMipMap */
+ if (!strcmp(argv[a],"linearmipmap"))
+ {
+ set_linear_mipmap(1); //linearMipMap = 1;
+ }
+
+
+ } /* if (*(argv[a+1]) == '=') */
+ } /* if(++a < argc) */
+ break;
+ }
+ case 'f':
+ a++;
+ if (G.scene) {
+ if (a < argc) {
+ int frame= MIN2(MAXFRAME, MAX2(1, atoi(argv[a])));
+ Render *re= RE_NewRender(G.scene->id.name);
+ RE_BlenderAnim(re, G.scene, frame, frame);
+ }
+ } else {
+ printf("\nError: no blend loaded. cannot use '-f'.\n");
+ }
+ break;
+ case 'a':
+ if (G.scene) {
+ Render *re= RE_NewRender(G.scene->id.name);
+ RE_BlenderAnim(re, G.scene, G.scene->r.sfra, G.scene->r.efra);
+ } else {
+ printf("\nError: no blend loaded. cannot use '-a'.\n");
+ }
+ break;
+ case 'S':
+ if(++a < argc) {
+ set_scene_name(argv[a]);
+ }
+ break;
+ case 's':
+ a++;
+ if(G.scene) {
+ int frame= MIN2(MAXFRAME, MAX2(1, atoi(argv[a])));
+ if (a < argc) (G.scene->r.sfra) = frame;
+ } else {
+ printf("\nError: no blend loaded. cannot use '-s'.\n");
+ }
+ break;
+ case 'e':
+ a++;
+ if(G.scene) {
+ int frame= MIN2(MAXFRAME, MAX2(1, atoi(argv[a])));
+ if (a < argc) (G.scene->r.efra) = frame;
+ } else {
+ printf("\nError: no blend loaded. cannot use '-e'.\n");
+ }
+ break;
+ case 'P':
+ a++;
+ if (a < argc) BPY_run_python_script (argv[a]);
+ else printf("\nError: you must specify a Python script after '-P '.\n");
+ break;
+ case 'o':
+ a++;
+ if (a < argc){
+ if(G.scene) {
+ BLI_strncpy(G.scene->r.pic, argv[a], FILE_MAXDIR);
+ } else {
+ printf("\nError: no blend loaded. cannot use '-o'.\n");
+ }
+ } else {
+ printf("\nError: you must specify a path after '-o '.\n");
+ }
+ break;
+ case 'F':
+ a++;
+ if (a < argc){
+ if(!G.scene) {
+ printf("\nError: no blend loaded. order the arguments so '-F ' is after the blend is loaded.\n");
+ } else {
+ if (!strcmp(argv[a],"TGA")) G.scene->r.imtype = R_TARGA;
+ else if (!strcmp(argv[a],"IRIS")) G.scene->r.imtype = R_IRIS;
+ else if (!strcmp(argv[a],"HAMX")) G.scene->r.imtype = R_HAMX;
+ else if (!strcmp(argv[a],"FTYPE")) G.scene->r.imtype = R_FTYPE;
+ else if (!strcmp(argv[a],"JPEG")) G.scene->r.imtype = R_JPEG90;
+ else if (!strcmp(argv[a],"MOVIE")) G.scene->r.imtype = R_MOVIE;
+ else if (!strcmp(argv[a],"IRIZ")) G.scene->r.imtype = R_IRIZ;
+ else if (!strcmp(argv[a],"RAWTGA")) G.scene->r.imtype = R_RAWTGA;
+ else if (!strcmp(argv[a],"AVIRAW")) G.scene->r.imtype = R_AVIRAW;
+ else if (!strcmp(argv[a],"AVIJPEG")) G.scene->r.imtype = R_AVIJPEG;
+ else if (!strcmp(argv[a],"PNG")) G.scene->r.imtype = R_PNG;
+ else if (!strcmp(argv[a],"AVICODEC")) G.scene->r.imtype = R_AVICODEC;
+ else if (!strcmp(argv[a],"QUICKTIME")) G.scene->r.imtype = R_QUICKTIME;
+ else if (!strcmp(argv[a],"BMP")) G.scene->r.imtype = R_BMP;
+ else if (!strcmp(argv[a],"HDR")) G.scene->r.imtype = R_RADHDR;
+ else if (!strcmp(argv[a],"TIFF")) G.scene->r.imtype = R_IRIS;
+ else if (!strcmp(argv[a],"EXR")) G.scene->r.imtype = R_OPENEXR;
+ else if (!strcmp(argv[a],"MPEG")) G.scene->r.imtype = R_FFMPEG;
+ else if (!strcmp(argv[a],"FRAMESERVER")) G.scene->r.imtype = R_FRAMESERVER;
+ else if (!strcmp(argv[a],"CINEON")) G.scene->r.imtype = R_CINEON;
+ else if (!strcmp(argv[a],"DPX")) G.scene->r.imtype = R_DPX;
+ else printf("\nError: Format from '-F ' not known.\n");
+ }
+ } else {
+ printf("\nError: no blend loaded. cannot use '-x'.\n");
+ }
+ break;
+
+ case 't':
+ a++;
+ if(G.background) {
+ RE_set_max_threads(atoi(argv[a]));
+ }
+ break;
+ case 'x': /* extension */
+ a++;
+ if (a < argc) {
+ if(G.scene) {
+ if (argv[a][0] == '0') {
+ G.scene->r.scemode &= ~R_EXTENSION;
+ } else if (argv[a][0] == '1') {
+ G.scene->r.scemode |= R_EXTENSION;
+ } else {
+ printf("\nError: Use '-x 1' or '-x 0' To set the extension option.\n");
+ }
+ } else {
+ printf("\nError: no blend loaded. order the arguments so '-o ' is after '-x '.\n");
+ }
+ } else {
+ printf("\nError: you must specify a path after '- '.\n");
+ }
+ break;
+ }
+ }
+ else {
+ BKE_read_file(argv[a], NULL);
+ sound_initialize_sounds();
+ }
+ }
+
+ if(G.background) {
+ /* actually incorrect, but works for now (ton) */
+ exit_usiblender();
+ }
+
+ setscreen(G.curscreen);
+
+ if(G.main->scene.first==0) {
+ sce= add_scene("1");
+ set_scene(sce);
+ }
+
+ BKE_write_undo("original"); /* save current state */
+ screenmain();
+
+ return 0;
+} /* end of int main(argc,argv) */
+
+static void error_cb(char *err)
+{
+ error("%s", err);
+}
+
+static void mem_error_cb(char *errorStr)
+{
+ fprintf(stderr, errorStr);
+ fflush(stderr);
+}
+
+void setCallbacks(void)
+{
+ /* Error output from the alloc routines: */
+ MEM_set_error_callback(mem_error_cb);
+
+
+ /* BLI_blenlib: */
+
+ BLI_setErrorCallBack(error_cb); /* */
+ BLI_setInterruptCallBack(blender_test_break);
+
+}
diff --git a/source/darwin/Makefile b/source/darwin/Makefile
new file mode 100644
index 00000000000..85c2c02852f
--- /dev/null
+++ b/source/darwin/Makefile
@@ -0,0 +1,58 @@
+#
+# $Id: Makefile,v 1.7 2003/05/12 18:12:25 sgefant Exp $
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by 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
+
+DIR = $(OCGDIR)/$(DEBUG_DIR)
+
+all::
+ @# set up directory structure for the OSX aplication bundle
+ @echo "---> creating directory structure for $(APPLICATION)"
+ @rm -rf $(DIR)/bin/$(APPLICATION).app
+ @cp -R $(APPLICATION).app $(DIR)/bin
+ @cat $(APPLICATION).app/Contents/Info.plist | sed s/VERSION/`cat ../../release/VERSION`/ | sed s/DATE/`date +'%Y-%b-%d'`/ > $(DIR)/bin/$(APPLICATION).app/Contents/Info.plist
+ @echo "---> copying binary"
+ @cp $(DIR)/bin/$(APPLICATION) $(DIR)/bin/$(APPLICATION).app/Contents/MacOS/
+ @echo "---> adding excutable attributes"
+ @chmod +x $(DIR)/bin/$(APPLICATION).app/Contents/MacOS/$(APPLICATION)
+ifeq ($(APPLICATION), blender)
+ @echo "---> copying message files"
+ @cp -R $(NANBLENDERHOME)/bin/.blender/locale $(DIR)/bin/$(APPLICATION).app/Contents/Resources
+ @echo "---> copying .Blanguages"
+ @cp $(NANBLENDERHOME)/bin/.blender/.Blanguages $(DIR)/bin/$(APPLICATION).app/Contents/Resources
+ @echo "---> copying .blender/ scripts"
+ @cp -R $(NANBLENDERHOME)/bin/.blender $(DIR)/bin/$(APPLICATION).app/Contents/MacOS
+ @cp -R $(NANBLENDERHOME)/release/scripts $(DIR)/bin/$(APPLICATION).app/Contents/MacOS/.blender/
+endif
+ @echo "---> removing CVS directories and Mac hidden files from distribution"
+ @find $(DIR)/bin/$(APPLICATION).app -name CVS -prune -exec rm -rf {} \;
+ @find $(DIR)/bin/$(APPLICATION).app -name .DS_Store -exec rm -f {} \;
diff --git a/source/darwin/blender.app/Contents/Info.plist b/source/darwin/blender.app/Contents/Info.plist
new file mode 100644
index 00000000000..0accb3e9940
--- /dev/null
+++ b/source/darwin/blender.app/Contents/Info.plist
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+
+ <key>CFBundleExecutable</key>
+ <string>blender</string>
+
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+
+ <key>CFBundleIconFile</key>
+ <string>blender icon.icns</string>
+
+ <key>CFBundleName</key>
+ <string>Blender</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.blenderfoundation.blender</string>
+
+ <key>CFBundleVersion</key>
+ <string>VERSION, DATE, Blender Foundation</string>
+ <key>CFBundleShortVersionString</key>
+ <string>VERSION</string>
+ <key>CFBundleGetInfoString</key>
+ <string>VERSION, DATE, Blender Foundation</string>
+
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeIconFile</key>
+ <string>blender file icon.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>Blender File</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>BLND</string>
+ </array>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>blend</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>LSIsAppleDefaultForType</key>
+ <true/>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/source/darwin/blender.app/Contents/MacOS/blender b/source/darwin/blender.app/Contents/MacOS/blender
new file mode 100644
index 00000000000..5e05e74a307
--- /dev/null
+++ b/source/darwin/blender.app/Contents/MacOS/blender
@@ -0,0 +1 @@
+placeholder
diff --git a/source/darwin/blender.app/Contents/PkgInfo b/source/darwin/blender.app/Contents/PkgInfo
new file mode 100644
index 00000000000..bd04210fb49
--- /dev/null
+++ b/source/darwin/blender.app/Contents/PkgInfo
@@ -0,0 +1 @@
+APPL???? \ No newline at end of file
diff --git a/source/darwin/blender.app/Contents/Resources/blender file icon.icns b/source/darwin/blender.app/Contents/Resources/blender file icon.icns
new file mode 100644
index 00000000000..78d84cf70c3
--- /dev/null
+++ b/source/darwin/blender.app/Contents/Resources/blender file icon.icns
Binary files differ
diff --git a/source/darwin/blender.app/Contents/Resources/blender icon.icns b/source/darwin/blender.app/Contents/Resources/blender icon.icns
new file mode 100644
index 00000000000..a9b352f9a1c
--- /dev/null
+++ b/source/darwin/blender.app/Contents/Resources/blender icon.icns
Binary files differ
diff --git a/source/darwin/blendercreator.app/Contents/Info.plist b/source/darwin/blendercreator.app/Contents/Info.plist
new file mode 100644
index 00000000000..08709cd26e3
--- /dev/null
+++ b/source/darwin/blendercreator.app/Contents/Info.plist
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+
+ <key>CFBundleExecutable</key>
+ <string>blendercreator</string>
+
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+
+ <key>CFBundleIconFile</key>
+ <string>blender creator icon.icns</string>
+
+ <key>CFBundleName</key>
+ <string>BlenderCreator</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.nantechnologies.blendercreator</string>
+
+ <key>CFBundleVersion</key>
+ <string>VERSION, DATE, Copyright NaN Technologies BV</string>
+ <key>CFBundleShortVersionString</key>
+ <string>VERSION</string>
+ <key>CFBundleGetInfoString</key>
+ <string>VERSION, DATE, Copyright NaN Technologies BV</string>
+
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeIconFile</key>
+ <string>blender file icon.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>Blender File</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>BLND</string>
+ </array>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>blend</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>LSIsAppleDefaultForType</key>
+ <true/>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/source/darwin/blendercreator.app/Contents/MacOS/blendercreator b/source/darwin/blendercreator.app/Contents/MacOS/blendercreator
new file mode 100644
index 00000000000..5e05e74a307
--- /dev/null
+++ b/source/darwin/blendercreator.app/Contents/MacOS/blendercreator
@@ -0,0 +1 @@
+placeholder
diff --git a/source/darwin/blendercreator.app/Contents/PkgInfo b/source/darwin/blendercreator.app/Contents/PkgInfo
new file mode 100644
index 00000000000..bd04210fb49
--- /dev/null
+++ b/source/darwin/blendercreator.app/Contents/PkgInfo
@@ -0,0 +1 @@
+APPL???? \ No newline at end of file
diff --git a/source/darwin/blendercreator.app/Contents/Resources/blender creator icon.icns b/source/darwin/blendercreator.app/Contents/Resources/blender creator icon.icns
new file mode 100644
index 00000000000..a9b352f9a1c
--- /dev/null
+++ b/source/darwin/blendercreator.app/Contents/Resources/blender creator icon.icns
Binary files differ
diff --git a/source/darwin/blendercreator.app/Contents/Resources/blender file icon.icns b/source/darwin/blendercreator.app/Contents/Resources/blender file icon.icns
new file mode 100644
index 00000000000..78d84cf70c3
--- /dev/null
+++ b/source/darwin/blendercreator.app/Contents/Resources/blender file icon.icns
Binary files differ
diff --git a/source/darwin/blenderplayer.app/Contents/Info.plist b/source/darwin/blenderplayer.app/Contents/Info.plist
new file mode 100644
index 00000000000..18c4438884a
--- /dev/null
+++ b/source/darwin/blenderplayer.app/Contents/Info.plist
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>blend</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>blender file icon.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>Blender File</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>BLND</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>LSIsAppleDefaultForType</key>
+ <false/>
+ </dict>
+ </array>
+ <key>CFBundleExecutable</key>
+ <string>blenderplayer</string>
+ <key>CFBundleGetInfoString</key>
+ <string>VERSION, DATE, Blender Foundation</string>
+ <key>CFBundleIconFile</key>
+ <string>blender player icon.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.blenderfoundation.blenderplayer</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>BlenderPlayer</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>VERSION</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>VERSION, DATE, Blender Foundation</string>
+</dict>
+</plist>
diff --git a/source/darwin/blenderplayer.app/Contents/MacOS/blenderplayer b/source/darwin/blenderplayer.app/Contents/MacOS/blenderplayer
new file mode 100644
index 00000000000..5e05e74a307
--- /dev/null
+++ b/source/darwin/blenderplayer.app/Contents/MacOS/blenderplayer
@@ -0,0 +1 @@
+placeholder
diff --git a/source/darwin/blenderplayer.app/Contents/PkgInfo b/source/darwin/blenderplayer.app/Contents/PkgInfo
new file mode 100644
index 00000000000..bd04210fb49
--- /dev/null
+++ b/source/darwin/blenderplayer.app/Contents/PkgInfo
@@ -0,0 +1 @@
+APPL???? \ No newline at end of file
diff --git a/source/darwin/blenderplayer.app/Contents/Resources/blender file icon.icns b/source/darwin/blenderplayer.app/Contents/Resources/blender file icon.icns
new file mode 100644
index 00000000000..78d84cf70c3
--- /dev/null
+++ b/source/darwin/blenderplayer.app/Contents/Resources/blender file icon.icns
Binary files differ
diff --git a/source/darwin/blenderplayer.app/Contents/Resources/blender player icon.icns b/source/darwin/blenderplayer.app/Contents/Resources/blender player icon.icns
new file mode 100644
index 00000000000..a9b352f9a1c
--- /dev/null
+++ b/source/darwin/blenderplayer.app/Contents/Resources/blender player icon.icns
Binary files differ
diff --git a/source/darwin/blenderpublisher.app/Contents/Info.plist b/source/darwin/blenderpublisher.app/Contents/Info.plist
new file mode 100644
index 00000000000..f22de5a4460
--- /dev/null
+++ b/source/darwin/blenderpublisher.app/Contents/Info.plist
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+
+ <key>CFBundleExecutable</key>
+ <string>blenderpublisher</string>
+
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+
+ <key>CFBundleIconFile</key>
+ <string>blender publisher icon.icns</string>
+
+ <key>CFBundleName</key>
+ <string>BlenderPublisher</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.nantechnologies.blenderpublisher</string>
+
+ <key>CFBundleVersion</key>
+ <string>VERSION, DATE, Copyright NaN Technologies BV</string>
+ <key>CFBundleShortVersionString</key>
+ <string>VERSION</string>
+ <key>CFBundleGetInfoString</key>
+ <string>VERSION, DATE, Copyright NaN Technologies BV</string>
+
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeIconFile</key>
+ <string>blender file icon.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>Blender File</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>BLND</string>
+ </array>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>blend</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>LSIsAppleDefaultForType</key>
+ <true/>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/source/darwin/blenderpublisher.app/Contents/MacOS/blenderpublisher b/source/darwin/blenderpublisher.app/Contents/MacOS/blenderpublisher
new file mode 100644
index 00000000000..5e05e74a307
--- /dev/null
+++ b/source/darwin/blenderpublisher.app/Contents/MacOS/blenderpublisher
@@ -0,0 +1 @@
+placeholder
diff --git a/source/darwin/blenderpublisher.app/Contents/PkgInfo b/source/darwin/blenderpublisher.app/Contents/PkgInfo
new file mode 100644
index 00000000000..bd04210fb49
--- /dev/null
+++ b/source/darwin/blenderpublisher.app/Contents/PkgInfo
@@ -0,0 +1 @@
+APPL???? \ No newline at end of file
diff --git a/source/darwin/blenderpublisher.app/Contents/Resources/blender file icon.icns b/source/darwin/blenderpublisher.app/Contents/Resources/blender file icon.icns
new file mode 100644
index 00000000000..a6041899cfb
--- /dev/null
+++ b/source/darwin/blenderpublisher.app/Contents/Resources/blender file icon.icns
Binary files differ
diff --git a/source/darwin/blenderpublisher.app/Contents/Resources/blender publisher icon.icns b/source/darwin/blenderpublisher.app/Contents/Resources/blender publisher icon.icns
new file mode 100644
index 00000000000..90784597129
--- /dev/null
+++ b/source/darwin/blenderpublisher.app/Contents/Resources/blender publisher icon.icns
Binary files differ
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
new file mode 100644
index 00000000000..0c42a35c808
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
@@ -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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Blender's Ketsji startpoint
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <signal.h>
+
+#ifdef WIN32
+// don't show stl-warnings
+#pragma warning (disable:4786)
+#endif
+
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#endif
+
+#include "KX_BlenderGL.h"
+#include "KX_BlenderCanvas.h"
+#include "KX_BlenderKeyboardDevice.h"
+#include "KX_BlenderMouseDevice.h"
+#include "KX_BlenderRenderTools.h"
+#include "KX_BlenderSystem.h"
+#include "BL_Material.h"
+
+#include "KX_KetsjiEngine.h"
+#include "KX_BlenderSceneConverter.h"
+#include "KX_PythonInit.h"
+#include "KX_PyConstraintBinding.h"
+
+#include "RAS_OpenGLRasterizer.h"
+#include "RAS_VAOpenGLRasterizer.h"
+#include "RAS_ListRasterizer.h"
+#include "RAS_GLExtensionManager.h"
+
+#include "NG_LoopBackNetworkDeviceInterface.h"
+#include "SND_DeviceManager.h"
+
+#include "SYS_System.h"
+
+ /***/
+
+#include "DNA_view3d_types.h"
+#include "DNA_screen_types.h"
+#include "BKE_global.h"
+#include "BIF_screen.h"
+#include "BIF_scrarea.h"
+
+#include "BKE_main.h"
+#include "BLI_blenlib.h"
+#include "BLO_readfile.h"
+#include "DNA_scene_types.h"
+ /***/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "BSE_headerbuttons.h"
+void update_for_newframe();
+#ifdef __cplusplus
+}
+#endif
+
+static BlendFileData *load_game_data(char *filename) {
+ BlendReadError error;
+ //this doesn't work anymore for relative paths, so use BLO_read_from_memory instead
+ //BlendFileData *bfd= BLO_read_from_file(filename, &error);
+ FILE* file = fopen(filename,"rb");
+ BlendFileData *bfd = 0;
+ if (file)
+ {
+ fseek(file, 0L, SEEK_END);
+ int len= ftell(file);
+ fseek(file, 0L, SEEK_SET);
+ char* filebuffer= new char[len];//MEM_mallocN(len, "text_buffer");
+ int sizeread = fread(filebuffer,len,1,file);
+ if (sizeread==1)
+ {
+ bfd = BLO_read_from_memory(filebuffer, len, &error);
+ }
+ fclose(file);
+ }
+
+ if (!bfd) {
+ printf("Loading %s failed: %s\n", filename, BLO_bre_as_string(error));
+ }
+
+ return bfd;
+}
+
+extern "C" void StartKetsjiShell(struct ScrArea *area,
+ char* scenename,
+ struct Main* maggie1,
+ struct SpaceIpo *sipo,
+ int always_use_expand_framing)
+{
+ int exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
+
+ Main* blenderdata = maggie1;
+
+ char* startscenename = scenename;
+ char pathname[160];
+ strcpy (pathname, blenderdata->name);
+ STR_String exitstring = "";
+ BlendFileData *bfd= NULL;
+
+ bgl::InitExtensions(1);
+
+ do
+ {
+ View3D *v3d= (View3D*) area->spacedata.first;
+
+ // get some preferences
+ SYS_SystemHandle syshandle = SYS_GetSystem();
+ bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
+ bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0);
+ bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
+ bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
+ bool game2ipo = (SYS_GetCommandLineInt(syshandle, "game2ipo", 0) != 0);
+ bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0);
+ bool usemat = false;
+
+ #ifdef GL_ARB_multitexture
+ if(bgl::RAS_EXT_support._ARB_multitexture && bgl::QueryVersion(1, 1)) {
+ usemat = (SYS_GetCommandLineInt(syshandle, "blender_material", 0) != 0);
+ int unitmax=0;
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&unitmax);
+ bgl::max_texture_units = MAXTEX>unitmax?unitmax:MAXTEX;
+ //std::cout << "using(" << bgl::max_texture_units << ") of(" << unitmax << ") texture units." << std::endl;
+ } else {
+ bgl::max_texture_units = 0;
+ }
+ #endif
+
+
+ // create the canvas, rasterizer and rendertools
+ RAS_ICanvas* canvas = new KX_BlenderCanvas(area);
+ canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
+ RAS_IRenderTools* rendertools = new KX_BlenderRenderTools();
+ RAS_IRasterizer* rasterizer = NULL;
+
+ // let's see if we want to use vertexarrays or not
+ int usevta = SYS_GetCommandLineInt(syshandle,"vertexarrays",1);
+ bool useVertexArrays = (usevta > 0);
+
+ bool lock_arrays = (displaylists && useVertexArrays);
+
+ if(displaylists && !useVertexArrays)
+ rasterizer = new RAS_ListRasterizer(canvas);
+ else if (useVertexArrays && bgl::QueryVersion(1, 1))
+ rasterizer = new RAS_VAOpenGLRasterizer(canvas, lock_arrays);
+ else
+ rasterizer = new RAS_OpenGLRasterizer(canvas);
+
+ // create the inputdevices
+ KX_BlenderKeyboardDevice* keyboarddevice = new KX_BlenderKeyboardDevice();
+ KX_BlenderMouseDevice* mousedevice = new KX_BlenderMouseDevice();
+
+ // create a networkdevice
+ NG_NetworkDeviceInterface* networkdevice = new
+ NG_LoopBackNetworkDeviceInterface();
+
+ // get an audiodevice
+ SND_DeviceManager::Subscribe();
+ SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
+ audiodevice->UseCD();
+
+ // create a ketsji/blendersystem (only needed for timing and stuff)
+ KX_BlenderSystem* kxsystem = new KX_BlenderSystem();
+
+ // create the ketsjiengine
+ KX_KetsjiEngine* ketsjiengine = new KX_KetsjiEngine(kxsystem);
+
+ // set the devices
+ ketsjiengine->SetKeyboardDevice(keyboarddevice);
+ ketsjiengine->SetMouseDevice(mousedevice);
+ ketsjiengine->SetNetworkDevice(networkdevice);
+ ketsjiengine->SetCanvas(canvas);
+ ketsjiengine->SetRenderTools(rendertools);
+ ketsjiengine->SetRasterizer(rasterizer);
+ ketsjiengine->SetNetworkDevice(networkdevice);
+ ketsjiengine->SetAudioDevice(audiodevice);
+ ketsjiengine->SetUseFixedTime(usefixed);
+ ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
+
+
+
+ // some blender stuff
+ MT_CmMatrix4x4 projmat;
+ MT_CmMatrix4x4 viewmat;
+ int i;
+
+ for (i = 0; i < 16; i++)
+ {
+ float *viewmat_linear= (float*) v3d->viewmat;
+ viewmat.setElem(i, viewmat_linear[i]);
+ }
+ for (i = 0; i < 16; i++)
+ {
+ float *projmat_linear = (float*) area->winmat;
+ projmat.setElem(i, projmat_linear[i]);
+ }
+
+ float camzoom = (1.41421 + (v3d->camzoom / 50.0));
+ camzoom *= camzoom;
+ camzoom = 4.0 / camzoom;
+
+ ketsjiengine->SetDrawType(v3d->drawtype);
+ ketsjiengine->SetCameraZoom(camzoom);
+
+ // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file
+ if (exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME || exitrequested == KX_EXIT_REQUEST_RESTART_GAME)
+ {
+ exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
+ if (bfd) BLO_blendfiledata_free(bfd);
+
+ char basedpath[160];
+ // base the actuator filename with respect
+ // to the original file working directory
+ if (exitstring != "")
+ strcpy(basedpath, exitstring.Ptr());
+
+ BLI_convertstringcode(basedpath, pathname, 0);
+ bfd = load_game_data(basedpath);
+
+ // if it wasn't loaded, try it forced relative
+ if (!bfd)
+ {
+ // just add "//" in front of it
+ char temppath[162];
+ strcpy(temppath, "//");
+ strcat(temppath, basedpath);
+
+ BLI_convertstringcode(temppath, pathname, 0);
+ bfd = load_game_data(temppath);
+ }
+
+ // if we got a loaded blendfile, proceed
+ if (bfd)
+ {
+ blenderdata = bfd->main;
+ startscenename = bfd->curscene->id.name + 2;
+ }
+ // else forget it, we can't find it
+ else
+ {
+ exitrequested = KX_EXIT_REQUEST_QUIT_GAME;
+ }
+ }
+
+ Scene *blscene = NULL;
+ if (!bfd)
+ {
+ blscene = (Scene*) blenderdata->scene.first;
+ for (Scene *sce= (Scene*) blenderdata->scene.first; sce; sce= (Scene*) sce->id.next)
+ {
+ if (startscenename == (sce->id.name+2))
+ {
+ blscene = sce;
+ break;
+ }
+ }
+ } else {
+ blscene = bfd->curscene;
+ }
+
+ if (blscene)
+ {
+ int startFrame = blscene->r.cfra;
+ ketsjiengine->SetGame2IpoMode(game2ipo,startFrame);
+ }
+
+
+ // Quad buffered needs a special window.
+ if (blscene->r.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
+ rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->r.stereomode);
+
+ if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME)
+ {
+ if (v3d->persp != 2)
+ {
+ ketsjiengine->EnableCameraOverride(startscenename);
+ ketsjiengine->SetCameraOverrideUseOrtho((v3d->persp == 0));
+ ketsjiengine->SetCameraOverrideProjectionMatrix(projmat);
+ ketsjiengine->SetCameraOverrideViewMatrix(viewmat);
+ }
+
+ // create a scene converter, create and convert the startingscene
+ KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(blenderdata,sipo, ketsjiengine);
+ ketsjiengine->SetSceneConverter(sceneconverter);
+ sceneconverter->addInitFromFrame=false;
+ if (always_use_expand_framing)
+ sceneconverter->SetAlwaysUseExpandFraming(true);
+
+ if(usemat)
+ sceneconverter->SetMaterials(true);
+
+ KX_Scene* startscene = new KX_Scene(keyboarddevice,
+ mousedevice,
+ networkdevice,
+ audiodevice,
+ startscenename);
+
+ // some python things
+ PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest);
+ ketsjiengine->SetPythonDictionary(dictionaryobject);
+ initRasterizer(rasterizer, canvas);
+ PyObject *gameLogic = initGameLogic(startscene);
+ initGameKeys();
+ initPythonConstraintBinding();
+
+
+ if (sceneconverter)
+ {
+ // convert and add scene
+ sceneconverter->ConvertScene(
+ startscenename,
+ startscene,
+ dictionaryobject,
+ keyboarddevice,
+ rendertools,
+ canvas);
+ ketsjiengine->AddScene(startscene);
+
+ // init the rasterizer
+ rasterizer->Init();
+
+ // start the engine
+ ketsjiengine->StartEngine(true);
+
+ // the mainloop
+ while (!exitrequested)
+ {
+ // first check if we want to exit
+ exitrequested = ketsjiengine->GetExitCode();
+
+ // kick the engine
+ bool render = ketsjiengine->NextFrame();
+
+ if (render)
+ {
+ // render the frame
+ ketsjiengine->Render();
+ }
+
+ // test for the ESC key
+ while (qtest())
+ {
+ short val;
+ unsigned short event = extern_qread(&val);
+
+ if (keyboarddevice->ConvertBlenderEvent(event,val))
+ exitrequested = KX_EXIT_REQUEST_BLENDER_ESC;
+
+ /* Coordinate conversion... where
+ * should this really be?
+ */
+ if (event==MOUSEX) {
+ val = val - scrarea_get_win_x(area);
+ } else if (event==MOUSEY) {
+ val = scrarea_get_win_height(area) - (val - scrarea_get_win_y(area)) - 1;
+ }
+
+ mousedevice->ConvertBlenderEvent(event,val);
+ }
+ }
+ exitstring = ketsjiengine->GetExitString();
+
+ // when exiting the mainloop
+ dictionaryClearByHand(gameLogic);
+ ketsjiengine->StopEngine();
+ exitGamePythonScripting();
+ networkdevice->Disconnect();
+ }
+ if (sceneconverter)
+ {
+ delete sceneconverter;
+ sceneconverter = NULL;
+ }
+ }
+ // set the cursor back to normal
+ canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
+
+ // clean up some stuff
+ audiodevice->StopCD();
+
+ if (ketsjiengine)
+ {
+ delete ketsjiengine;
+ ketsjiengine = NULL;
+ }
+ if (kxsystem)
+ {
+ delete kxsystem;
+ kxsystem = NULL;
+ }
+ if (networkdevice)
+ {
+ delete networkdevice;
+ networkdevice = NULL;
+ }
+ if (keyboarddevice)
+ {
+ delete keyboarddevice;
+ keyboarddevice = NULL;
+ }
+ if (mousedevice)
+ {
+ delete mousedevice;
+ mousedevice = NULL;
+ }
+ if (rasterizer)
+ {
+ delete rasterizer;
+ rasterizer = NULL;
+ }
+ if (rendertools)
+ {
+ delete rendertools;
+ rendertools = NULL;
+ }
+ if (canvas)
+ {
+ delete canvas;
+ canvas = NULL;
+ }
+ SND_DeviceManager::Unsubscribe();
+
+ } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME);
+
+ if (bfd) BLO_blendfiledata_free(bfd);
+}
+
+extern "C" void StartKetsjiShellSimulation(struct ScrArea *area,
+ char* scenename,
+ struct Main* maggie,
+ struct SpaceIpo *sipo,
+ int always_use_expand_framing)
+{
+ int exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
+
+ Main* blenderdata = maggie;
+
+ char* startscenename = scenename;
+ char pathname[160];
+ strcpy (pathname, maggie->name);
+ STR_String exitstring = "";
+ BlendFileData *bfd= NULL;
+
+ bgl::InitExtensions(1);
+
+ do
+ {
+
+ // get some preferences
+ SYS_SystemHandle syshandle = SYS_GetSystem();
+ bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
+ bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0);
+ bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
+ bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
+ bool game2ipo = true;//(SYS_GetCommandLineInt(syshandle, "game2ipo", 0) != 0);
+ bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0);
+ bool usemat = false;
+
+ // create the canvas, rasterizer and rendertools
+ RAS_ICanvas* canvas = new KX_BlenderCanvas(area);
+ //canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
+ RAS_IRenderTools* rendertools = new KX_BlenderRenderTools();
+ RAS_IRasterizer* rasterizer = NULL;
+
+ // let's see if we want to use vertexarrays or not
+ int usevta = SYS_GetCommandLineInt(syshandle,"vertexarrays",1);
+ bool useVertexArrays = (usevta > 0);
+
+ bool lock_arrays = (displaylists && useVertexArrays);
+
+ if(displaylists && !useVertexArrays)
+ rasterizer = new RAS_ListRasterizer(canvas);
+ else if (useVertexArrays && bgl::QueryVersion(1, 1))
+ rasterizer = new RAS_VAOpenGLRasterizer(canvas, lock_arrays);
+ else
+ rasterizer = new RAS_OpenGLRasterizer(canvas);
+
+ // create the inputdevices
+ KX_BlenderKeyboardDevice* keyboarddevice = new KX_BlenderKeyboardDevice();
+ KX_BlenderMouseDevice* mousedevice = new KX_BlenderMouseDevice();
+
+ // create a networkdevice
+ NG_NetworkDeviceInterface* networkdevice = new
+ NG_LoopBackNetworkDeviceInterface();
+
+ // get an audiodevice
+ SND_DeviceManager::Subscribe();
+ SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
+ audiodevice->UseCD();
+
+ // create a ketsji/blendersystem (only needed for timing and stuff)
+ KX_BlenderSystem* kxsystem = new KX_BlenderSystem();
+
+ // create the ketsjiengine
+ KX_KetsjiEngine* ketsjiengine = new KX_KetsjiEngine(kxsystem);
+
+ int i;
+
+ Scene *blscene = NULL;
+ if (!bfd)
+ {
+ blscene = (Scene*) maggie->scene.first;
+ for (Scene *sce= (Scene*) maggie->scene.first; sce; sce= (Scene*) sce->id.next)
+ {
+ if (startscenename == (sce->id.name+2))
+ {
+ blscene = sce;
+ break;
+ }
+ }
+ } else {
+ blscene = bfd->curscene;
+ }
+ int cframe,startFrame;
+ if (blscene)
+ {
+ cframe=blscene->r.cfra;
+ startFrame = blscene->r.sfra;
+ blscene->r.cfra=startFrame;
+ update_for_newframe();
+ ketsjiengine->SetGame2IpoMode(game2ipo,startFrame);
+ }
+
+ // Quad buffered needs a special window.
+ if (blscene->r.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
+ rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->r.stereomode);
+
+ if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME)
+ {
+ // create a scene converter, create and convert the startingscene
+ KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(maggie,sipo, ketsjiengine);
+ ketsjiengine->SetSceneConverter(sceneconverter);
+ sceneconverter->addInitFromFrame=true;
+
+ if (always_use_expand_framing)
+ sceneconverter->SetAlwaysUseExpandFraming(true);
+
+ if(usemat)
+ sceneconverter->SetMaterials(true);
+
+ KX_Scene* startscene = new KX_Scene(keyboarddevice,
+ mousedevice,
+ networkdevice,
+ audiodevice,
+ startscenename);
+ // some python things
+ PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest);
+ ketsjiengine->SetPythonDictionary(dictionaryobject);
+ initRasterizer(rasterizer, canvas);
+ PyObject *gameLogic = initGameLogic(startscene);
+ initGameKeys();
+ initPythonConstraintBinding();
+
+ if (sceneconverter)
+ {
+ // convert and add scene
+ sceneconverter->ConvertScene(
+ startscenename,
+ startscene,
+ dictionaryobject,
+ keyboarddevice,
+ rendertools,
+ canvas);
+ ketsjiengine->AddScene(startscene);
+
+ // start the engine
+ ketsjiengine->StartEngine(false);
+
+ ketsjiengine->SetUseFixedTime(true);
+
+ ketsjiengine->SetTicRate(
+ (double) blscene->r.frs_sec /
+ (double) blscene->r.frs_sec_base);
+
+ // the mainloop
+ while ((blscene->r.cfra<=blscene->r.efra)&&(!exitrequested))
+ {
+ printf("frame %i\n",blscene->r.cfra);
+ // first check if we want to exit
+ exitrequested = ketsjiengine->GetExitCode();
+
+ // kick the engine
+ ketsjiengine->NextFrame();
+ blscene->r.cfra=blscene->r.cfra+1;
+ update_for_newframe();
+
+ }
+ exitstring = ketsjiengine->GetExitString();
+ }
+ if (sceneconverter)
+ {
+ delete sceneconverter;
+ sceneconverter = NULL;
+ }
+ }
+ blscene->r.cfra=cframe;
+ // set the cursor back to normal
+ canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
+
+ // clean up some stuff
+ audiodevice->StopCD();
+ if (ketsjiengine)
+ {
+ delete ketsjiengine;
+ ketsjiengine = NULL;
+ }
+ if (kxsystem)
+ {
+ delete kxsystem;
+ kxsystem = NULL;
+ }
+ if (networkdevice)
+ {
+ delete networkdevice;
+ networkdevice = NULL;
+ }
+ if (keyboarddevice)
+ {
+ delete keyboarddevice;
+ keyboarddevice = NULL;
+ }
+ if (mousedevice)
+ {
+ delete mousedevice;
+ mousedevice = NULL;
+ }
+ SND_DeviceManager::Unsubscribe();
+
+ } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME);
+ if (bfd) BLO_blendfiledata_free(bfd);
+}
diff --git a/source/gameengine/BlenderRoutines/CMakeLists.txt b/source/gameengine/BlenderRoutines/CMakeLists.txt
new file mode 100644
index 00000000000..764be732343
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/CMakeLists.txt
@@ -0,0 +1,40 @@
+
+FILE(GLOB SRC *.cpp)
+
+SET(INC
+ .
+ ../../../source/kernel/gen_system
+ ../../../intern/string
+ ../../../intern/guardedalloc
+ ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer
+ ../../../intern/bmfont
+ ../../../source/gameengine/Converter
+ ../../../source/blender/imbuf
+ ../../../intern/ghost/include
+ ../../../intern/moto/include
+ ../../../source/gameengine/Ketsji
+ ../../../source/blender/blenlib
+ ../../../source/blender/blenkernel
+ ../../../source/blender
+ ../../../source/blender/include
+ ../../../source/blender/makesdna
+ ../../../source/gameengine/Rasterizer
+ ../../../source/gameengine/GameLogic
+ ../../../source/gameengine/Expressions
+ ../../../source/gameengine/Network
+ ../../../source/gameengine/SceneGraph
+ ../../../source/gameengine/Physics/common
+ ../../../source/gameengine/Physics/Bullet
+ ../../../source/gameengine/Physics/Sumo
+ ../../../source/gameengine/Physics/Sumo/Fuzzics/include
+ ../../../source/gameengine/Network/LoopBackNetwork
+ ../../../intern/SoundSystem
+ ../../../source/blender/misc
+ ../../../source/blender/blenloader
+ ../../../extern/bullet2/src
+ ../../../extern/solid
+ ${PYTHON_INC}
+)
+
+BLENDERLIB(bf_blroutines "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_bloutines', sources, Split(incs), [], libtype=['game', 'game2', 'player'], priority=[0, 0, 55] , compileflags=cxxflags)
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
new file mode 100644
index 00000000000..03f78c4b145
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
@@ -0,0 +1,165 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "BIF_scrarea.h"
+#include "KX_BlenderCanvas.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_BlenderCanvas::KX_BlenderCanvas(struct ScrArea *area) :
+m_area(area)
+{
+}
+
+KX_BlenderCanvas::~KX_BlenderCanvas()
+{
+}
+
+void KX_BlenderCanvas::Init()
+{
+ glDepthFunc(GL_LEQUAL);
+}
+
+
+void KX_BlenderCanvas::SwapBuffers()
+{
+ BL_SwapBuffers();
+}
+
+void KX_BlenderCanvas::BeginFrame()
+{
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+
+}
+
+
+void KX_BlenderCanvas::EndFrame()
+{
+ // this is needed, else blender distorts a lot
+ glPopAttrib();
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+
+ glDisable(GL_FOG);
+}
+
+
+
+void KX_BlenderCanvas::ClearColor(float r,float g,float b,float a)
+{
+ glClearColor(r,g,b,a);
+}
+
+
+
+void KX_BlenderCanvas::ClearBuffer(int type)
+{
+ int ogltype = 0;
+
+ if (type & RAS_ICanvas::COLOR_BUFFER )
+ ogltype |= GL_COLOR_BUFFER_BIT;
+
+ if (type & RAS_ICanvas::DEPTH_BUFFER )
+ ogltype |= GL_DEPTH_BUFFER_BIT;
+ glClear(ogltype);
+}
+
+int KX_BlenderCanvas::GetWidth(
+) const {
+ return scrarea_get_win_width(m_area);
+}
+
+int KX_BlenderCanvas::GetHeight(
+) const {
+ return scrarea_get_win_height(m_area);
+}
+
+ void
+KX_BlenderCanvas::
+SetViewPort(
+ int x1, int y1,
+ int x2, int y2
+){
+ int vp_width = (x2 - x1) + 1;
+ int vp_height = (y2 - y1) + 1;
+ int minx = scrarea_get_win_x(m_area);
+ int miny = scrarea_get_win_y(m_area);
+
+ glViewport(minx + x1, miny + y1, vp_width, vp_height);
+ glScissor(minx + x1, miny + y1, vp_width, vp_height);
+}
+
+
+void KX_BlenderCanvas::SetMouseState(RAS_MouseState mousestate)
+{
+ switch (mousestate)
+ {
+ case MOUSE_INVISIBLE:
+ {
+ BL_HideMouse();
+ break;
+ }
+ case MOUSE_WAIT:
+ {
+ BL_WaitMouse();
+ break;
+ }
+ case MOUSE_NORMAL:
+ {
+ BL_NormalMouse();
+ break;
+ }
+ default:
+ {
+ }
+ }
+}
+
+
+
+// (0,0) is top left, (width,height) is bottom right
+void KX_BlenderCanvas::SetMousePosition(int x,int y)
+{
+ int winX = scrarea_get_win_x(m_area);
+ int winY = scrarea_get_win_y(m_area);
+ int winH = scrarea_get_win_height(m_area);
+
+ BL_warp_pointer(winX + x, winY + (winH-y-1));
+}
+
+
+
+void KX_BlenderCanvas::MakeScreenShot(const char* filename)
+{
+ BL_MakeScreenShot(m_area, filename);
+}
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
new file mode 100644
index 00000000000..23258f5ea81
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
@@ -0,0 +1,171 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_BLENDERCANVAS
+#define __KX_BLENDERCANVAS
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#else
+#include <GL/gl.h>
+#endif
+
+#include "RAS_ICanvas.h"
+#include "RAS_Rect.h"
+
+#include "KX_BlenderGL.h"
+
+struct ScrArea;
+
+/**
+ * 2D Blender device context abstraction.
+ * The connection from 3d rendercontext to 2d Blender surface embedding.
+ */
+
+class KX_BlenderCanvas : public RAS_ICanvas
+{
+private:
+ /** Rect that defines the area used for rendering,
+ relative to the context */
+ RAS_Rect m_displayarea;
+
+public:
+ /* Construct a new canvas.
+ *
+ * @param area The Blender ScrArea to run the game within.
+ */
+ KX_BlenderCanvas(struct ScrArea* area);
+ ~KX_BlenderCanvas();
+
+ void
+ Init(
+ );
+
+ void
+ SwapBuffers(
+ );
+ void
+ Resize(
+ int width,
+ int height
+ );
+
+ void
+ BeginFrame(
+ );
+
+ void
+ EndFrame(
+ );
+
+ void
+ ClearColor(
+ float r,
+ float g,
+ float b,
+ float a
+ );
+
+ void
+ ClearBuffer(
+ int type
+ );
+
+ int
+ GetWidth(
+ ) const ;
+
+ int
+ GetHeight(
+ ) const ;
+
+ const
+ RAS_Rect &
+ GetDisplayArea(
+ ) const {
+ return m_displayarea;
+ };
+
+ RAS_Rect &
+ GetDisplayArea(
+ ) {
+ return m_displayarea;
+ };
+
+ void
+ SetViewPort(
+ int x1, int y1,
+ int x2, int y2
+ );
+
+ void
+ SetMouseState(
+ RAS_MouseState mousestate
+ );
+
+ void
+ SetMousePosition(
+ int x,
+ int y
+ );
+
+ void
+ MakeScreenShot(
+ const char* filename
+ );
+
+ /**
+ * Nothing needs be done for BlenderCanvas
+ * Begin/End Draw, as the game engine GL context
+ * is always current/active.
+ */
+
+ bool
+ BeginDraw(
+ ) {
+ return true;
+ };
+
+ void
+ EndDraw(
+ ) {
+ };
+
+private:
+ /** Blender area the game engine is running within */
+ struct ScrArea* m_area;
+};
+
+#endif // __KX_BLENDERCANVAS
+
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp
new file mode 100644
index 00000000000..8f7609aed74
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp
@@ -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) 2001-2002 by 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 "KX_BlenderGL.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*
+ * This little block needed for linking to Blender...
+ */
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "BMF_Api.h"
+
+
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif
+#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
+#include "RAS_OpenGLRasterizer/ARB_multitexture.h"
+#include "BL_Material.h" // MAXTEX
+
+/* Data types encoding the game world: */
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_world_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_image_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_material_types.h"
+
+#include "BKE_global.h"
+#include "BKE_bmfont.h"
+#include "BKE_image.h"
+
+#include "BIF_gl.h"
+extern "C" {
+#include "BDR_drawmesh.h"
+#include "BIF_mywindow.h"
+#include "BIF_toolbox.h"
+#include "BIF_graphics.h" /* For CURSOR_NONE CURSOR_WAIT CURSOR_STD */
+
+}
+
+/* end of blender block */
+
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#else
+#include <GL/gl.h>
+#endif
+
+/* was in drawmesh.c */
+void spack(unsigned int ucol)
+{
+ char *cp= (char *)&ucol;
+
+ glColor3ub(cp[3], cp[2], cp[1]);
+}
+
+void BL_warp_pointer(int x,int y)
+{
+ warp_pointer(x,y);
+}
+
+void BL_SwapBuffers()
+{
+ myswapbuffers();
+}
+
+void BL_RenderText(int mode,const char* textstr,int textlen,struct MTFace* tface,
+ unsigned int *col,float v1[3],float v2[3],float v3[3],float v4[3])
+{
+ Image* ima;
+
+ if(mode & TF_BMFONT) {
+ //char string[MAX_PROPSTRING];
+ int characters, index, character;
+ float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
+
+// bProperty *prop;
+
+ // string = "Frank van Beek";
+
+ characters = textlen;
+
+ ima = (struct Image*) tface->tpage;
+ if (ima == NULL) {
+ characters = 0;
+ }
+
+ if(!col) glColor3f(1.0f, 1.0f, 1.0f);
+
+ glPushMatrix();
+ for (index = 0; index < characters; index++) {
+ // lets calculate offset stuff
+ character = textstr[index];
+
+ // space starts at offset 1
+ // character = character - ' ' + 1;
+
+ matrixGlyph((ImBuf *)ima->ibufs.first, character, & centerx, &centery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
+
+ glBegin(GL_POLYGON);
+ // printf(" %c %f %f %f %f\n", character, tface->uv[0][0], tface->uv[0][1], );
+ // glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy);
+ glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy);
+
+ if(col) spack(col[0]);
+ // glVertex3fv(v1);
+ 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(col) spack(col[1]);
+ // glVertex3fv(v2);
+ 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(col) spack(col[2]);
+ // glVertex3fv(v3);
+ glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
+
+ if(v4) {
+ // glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, 1.0 - (1.0 - tface->uv[3][1]) * sizey - transy);
+ glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, (tface->uv[3][1] - centery) * sizey + transy);
+ if(col) spack(col[3]);
+ // glVertex3fv(v4);
+ glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
+ }
+ glEnd();
+
+ glTranslatef(advance, 0.0, 0.0);
+ }
+ glPopMatrix();
+
+ }
+}
+
+
+void DisableForText()
+{
+ if(glIsEnabled(GL_BLEND))
+ glDisable(GL_BLEND);
+
+ if(glIsEnabled(GL_LIGHTING)) {
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ }
+#ifdef GL_ARB_multitexture
+ for(int i=0; i<MAXTEX; i++) {
+ if(bgl::RAS_EXT_support._ARB_multitexture)
+ bgl::blActiveTextureARB(GL_TEXTURE0_ARB+i);
+#ifdef GL_ARB_texture_cube_map
+ if(bgl::RAS_EXT_support._ARB_texture_cube_map)
+ if(glIsEnabled(GL_TEXTURE_CUBE_MAP_ARB))
+ glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+#endif
+ if(glIsEnabled(GL_TEXTURE_2D))
+ glDisable(GL_TEXTURE_2D);
+ }
+#else//GL_ARB_multitexture
+ if(glIsEnabled(GL_TEXTURE_2D))
+ glDisable(GL_TEXTURE_2D);
+#endif
+}
+
+
+void BL_print_gamedebug_line(char* text, int xco, int yco, int width, int height)
+{
+ /* gl prepping */
+ DisableForText();
+ //glDisable(GL_TEXTURE_2D);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glOrtho(0, width,
+ 0, height, 0, 1);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glLoadIdentity();
+
+ /* the actual drawing */
+ glColor3ub(255, 255, 255);
+ glRasterPos2s(xco, height-yco);
+ BMF_DrawString(G.fonts, text);
+
+ glMatrixMode(GL_TEXTURE);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glEnable(GL_DEPTH_TEST);
+}
+
+void BL_print_gamedebug_line_padded(char* text, int xco, int yco, int width, int height)
+{
+ /* This is a rather important line :( The gl-mode hasn't been left
+ * behind quite as neatly as we'd have wanted to. I don't know
+ * what cause it, though :/ .*/
+ DisableForText();
+ //glDisable(GL_TEXTURE_2D);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glOrtho(0, width,
+ 0, height, 0, 1);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glLoadIdentity();
+
+ /* draw in black first*/
+ glColor3ub(0, 0, 0);
+ glRasterPos2s(xco+1, height-yco-1);
+ BMF_DrawString(G.fonts, text);
+ glColor3ub(255, 255, 255);
+ glRasterPos2s(xco, height-yco);
+ BMF_DrawString(G.fonts, text);
+
+ glMatrixMode(GL_TEXTURE);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glEnable(GL_DEPTH_TEST);
+}
+
+void BL_HideMouse()
+{
+ set_cursor(CURSOR_NONE);
+}
+
+
+void BL_WaitMouse()
+{
+ set_cursor(CURSOR_WAIT);
+}
+
+
+void BL_NormalMouse()
+{
+ set_cursor(CURSOR_STD);
+}
+#define MAX_FILE_LENGTH 512
+
+
+void BL_MakeScreenShot(struct ScrArea *area, const char* filename)
+{
+ char copyfilename[MAX_FILE_LENGTH];
+ strcpy(copyfilename,filename);
+
+ // filename read - only
+
+ /* XXX will need to change at some point */
+ BIF_screendump(0);
+
+ // write+read filename
+ write_screendump((char*) copyfilename);
+}
+
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.h b/source/gameengine/BlenderRoutines/KX_BlenderGL.h
new file mode 100644
index 00000000000..b0f97f1a76c
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.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 __BLENDERGL
+#define __BLENDERGL
+
+#ifdef __cplusplus
+extern "C" {
+#endif //__cplusplus
+
+struct ScrArea;
+
+// special swapbuffers, that takes care of which area (viewport) needs to be swapped
+void BL_SwapBuffers();
+
+void BL_warp_pointer(int x,int y);
+
+void BL_MakeScreenShot(struct ScrArea *area, const char* filename);
+
+void BL_HideMouse();
+void BL_NormalMouse();
+void BL_WaitMouse();
+
+void BL_RenderText(int mode,const char* textstr,int textlen,struct MTFace* tface,
+ unsigned int *col,float v1[3],float v2[3],float v3[3],float v4[3]);
+
+void BL_print_gamedebug_line(char* text, int xco, int yco, int width, int height);
+void BL_print_gamedebug_line_padded(char* text, int xco, int yco, int width, int height);
+
+
+
+#ifdef __cplusplus
+}
+#endif //__cplusplus
+
+#endif //__BLENDERGL
+
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.cpp b/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.cpp
new file mode 100644
index 00000000000..1423418924c
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.cpp
@@ -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 *****
+ */
+#include "KX_BlenderInputDevice.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h b/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h
new file mode 100644
index 00000000000..ed4eb65a769
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h
@@ -0,0 +1,223 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_BLENDERINPUTDEVICE
+#define __KX_BLENDERINPUTDEVICE
+
+#ifdef WIN32
+#pragma warning(disable : 4786) // shut off 255 char limit debug template warning
+#endif
+
+#include <map>
+
+/* need to be here for conversion purposes */
+#ifdef FREE_WINDOWS
+#undef HKEY
+#endif
+
+#include "mydevice.h"
+#include "SCA_IInputDevice.h"
+
+/**
+ Base Class for Blender specific inputdevices. Blender specific inputdevices are used when the gameengine is running in embedded mode instead of standalone mode.
+*/
+class BL_BlenderInputDevice : public SCA_IInputDevice
+{
+ // this map is Blender specific: a conversion between blender and ketsji enums
+ std::map<int,KX_EnumInputs> m_reverseKeyTranslateTable;
+public:
+ BL_BlenderInputDevice()
+ {
+
+ /* The reverse table. In order to not confuse ourselves, we */
+ /* immediately convert all events that come in to KX codes. */
+ m_reverseKeyTranslateTable[LEFTMOUSE ] = KX_LEFTMOUSE ;
+ m_reverseKeyTranslateTable[MIDDLEMOUSE ] = KX_MIDDLEMOUSE ;
+ m_reverseKeyTranslateTable[RIGHTMOUSE ] = KX_RIGHTMOUSE ;
+ m_reverseKeyTranslateTable[WHEELUPMOUSE ] = KX_WHEELUPMOUSE ;
+ m_reverseKeyTranslateTable[WHEELDOWNMOUSE ] = KX_WHEELDOWNMOUSE ;
+ m_reverseKeyTranslateTable[MOUSEX ] = KX_MOUSEX ;
+ m_reverseKeyTranslateTable[MOUSEY ] = KX_MOUSEY ;
+
+ // TIMERS
+
+ m_reverseKeyTranslateTable[TIMER0 ] = KX_TIMER0 ;
+ m_reverseKeyTranslateTable[TIMER1 ] = KX_TIMER1 ;
+ m_reverseKeyTranslateTable[TIMER2 ] = KX_TIMER2 ;
+ m_reverseKeyTranslateTable[TIMER3 ] = KX_TIMER3 ;
+
+ // SYSTEM
+
+ m_reverseKeyTranslateTable[KEYBD ] = KX_KEYBD ;
+ m_reverseKeyTranslateTable[RAWKEYBD ] = KX_RAWKEYBD ;
+ m_reverseKeyTranslateTable[REDRAW ] = KX_REDRAW ;
+ m_reverseKeyTranslateTable[INPUTCHANGE ] = KX_INPUTCHANGE ;
+ m_reverseKeyTranslateTable[QFULL ] = KX_QFULL ;
+ m_reverseKeyTranslateTable[WINFREEZE ] = KX_WINFREEZE ;
+ m_reverseKeyTranslateTable[WINTHAW ] = KX_WINTHAW ;
+ m_reverseKeyTranslateTable[WINCLOSE ] = KX_WINCLOSE ;
+ m_reverseKeyTranslateTable[WINQUIT ] = KX_WINQUIT ;
+ m_reverseKeyTranslateTable[Q_FIRSTTIME ] = KX_Q_FIRSTTIME ;
+
+ // standard keyboard
+
+ m_reverseKeyTranslateTable[AKEY ] = KX_AKEY ;
+ m_reverseKeyTranslateTable[BKEY ] = KX_BKEY ;
+ m_reverseKeyTranslateTable[CKEY ] = KX_CKEY ;
+ m_reverseKeyTranslateTable[DKEY ] = KX_DKEY ;
+ m_reverseKeyTranslateTable[EKEY ] = KX_EKEY ;
+ m_reverseKeyTranslateTable[FKEY ] = KX_FKEY ;
+ m_reverseKeyTranslateTable[GKEY ] = KX_GKEY ;
+ m_reverseKeyTranslateTable[HKEY ] = KX_HKEY ;
+ m_reverseKeyTranslateTable[IKEY ] = KX_IKEY ;
+ m_reverseKeyTranslateTable[JKEY ] = KX_JKEY ;
+ m_reverseKeyTranslateTable[KKEY ] = KX_KKEY ;
+ m_reverseKeyTranslateTable[LKEY ] = KX_LKEY ;
+ m_reverseKeyTranslateTable[MKEY ] = KX_MKEY ;
+ m_reverseKeyTranslateTable[NKEY ] = KX_NKEY ;
+ m_reverseKeyTranslateTable[OKEY ] = KX_OKEY ;
+ m_reverseKeyTranslateTable[PKEY ] = KX_PKEY ;
+ m_reverseKeyTranslateTable[QKEY ] = KX_QKEY ;
+ m_reverseKeyTranslateTable[RKEY ] = KX_RKEY ;
+ m_reverseKeyTranslateTable[SKEY ] = KX_SKEY ;
+ m_reverseKeyTranslateTable[TKEY ] = KX_TKEY ;
+ m_reverseKeyTranslateTable[UKEY ] = KX_UKEY ;
+ m_reverseKeyTranslateTable[VKEY ] = KX_VKEY ;
+ m_reverseKeyTranslateTable[WKEY ] = KX_WKEY ;
+ m_reverseKeyTranslateTable[XKEY ] = KX_XKEY ;
+ m_reverseKeyTranslateTable[YKEY ] = KX_YKEY ;
+ m_reverseKeyTranslateTable[ZKEY ] = KX_ZKEY ;
+
+ m_reverseKeyTranslateTable[ZEROKEY ] = KX_ZEROKEY ;
+ m_reverseKeyTranslateTable[ONEKEY ] = KX_ONEKEY ;
+ m_reverseKeyTranslateTable[TWOKEY ] = KX_TWOKEY ;
+ m_reverseKeyTranslateTable[THREEKEY ] = KX_THREEKEY ;
+ m_reverseKeyTranslateTable[FOURKEY ] = KX_FOURKEY ;
+ m_reverseKeyTranslateTable[FIVEKEY ] = KX_FIVEKEY ;
+ m_reverseKeyTranslateTable[SIXKEY ] = KX_SIXKEY ;
+ m_reverseKeyTranslateTable[SEVENKEY ] = KX_SEVENKEY ;
+ m_reverseKeyTranslateTable[EIGHTKEY ] = KX_EIGHTKEY ;
+ m_reverseKeyTranslateTable[NINEKEY ] = KX_NINEKEY ;
+
+ m_reverseKeyTranslateTable[CAPSLOCKKEY ] = KX_CAPSLOCKKEY ;
+
+ m_reverseKeyTranslateTable[LEFTCTRLKEY ] = KX_LEFTCTRLKEY ;
+ m_reverseKeyTranslateTable[LEFTALTKEY ] = KX_LEFTALTKEY ;
+ m_reverseKeyTranslateTable[RIGHTALTKEY ] = KX_RIGHTALTKEY ;
+ m_reverseKeyTranslateTable[RIGHTCTRLKEY ] = KX_RIGHTCTRLKEY ;
+ m_reverseKeyTranslateTable[RIGHTSHIFTKEY ] = KX_RIGHTSHIFTKEY ;
+ m_reverseKeyTranslateTable[LEFTSHIFTKEY ] = KX_LEFTSHIFTKEY ;
+
+ m_reverseKeyTranslateTable[ESCKEY ] = KX_ESCKEY ;
+ m_reverseKeyTranslateTable[TABKEY ] = KX_TABKEY ;
+ m_reverseKeyTranslateTable[RETKEY ] = KX_RETKEY ;
+ m_reverseKeyTranslateTable[SPACEKEY ] = KX_SPACEKEY ;
+ m_reverseKeyTranslateTable[LINEFEEDKEY ] = KX_LINEFEEDKEY ;
+ m_reverseKeyTranslateTable[BACKSPACEKEY ] = KX_BACKSPACEKEY ;
+ m_reverseKeyTranslateTable[DELKEY ] = KX_DELKEY ;
+ m_reverseKeyTranslateTable[SEMICOLONKEY ] = KX_SEMICOLONKEY ;
+ m_reverseKeyTranslateTable[PERIODKEY ] = KX_PERIODKEY ;
+ m_reverseKeyTranslateTable[COMMAKEY ] = KX_COMMAKEY ;
+ m_reverseKeyTranslateTable[QUOTEKEY ] = KX_QUOTEKEY ;
+ m_reverseKeyTranslateTable[ACCENTGRAVEKEY ] = KX_ACCENTGRAVEKEY ;
+ m_reverseKeyTranslateTable[MINUSKEY ] = KX_MINUSKEY ;
+ m_reverseKeyTranslateTable[SLASHKEY ] = KX_SLASHKEY ;
+ m_reverseKeyTranslateTable[BACKSLASHKEY ] = KX_BACKSLASHKEY ;
+ m_reverseKeyTranslateTable[EQUALKEY ] = KX_EQUALKEY ;
+ m_reverseKeyTranslateTable[LEFTBRACKETKEY ] = KX_LEFTBRACKETKEY ;
+ m_reverseKeyTranslateTable[RIGHTBRACKETKEY ] = KX_RIGHTBRACKETKEY ;
+
+ m_reverseKeyTranslateTable[LEFTARROWKEY ] = KX_LEFTARROWKEY ;
+ m_reverseKeyTranslateTable[DOWNARROWKEY ] = KX_DOWNARROWKEY ;
+ m_reverseKeyTranslateTable[RIGHTARROWKEY ] = KX_RIGHTARROWKEY ;
+ m_reverseKeyTranslateTable[UPARROWKEY ] = KX_UPARROWKEY ;
+
+ m_reverseKeyTranslateTable[PAD2 ] = KX_PAD2 ;
+ m_reverseKeyTranslateTable[PAD4 ] = KX_PAD4 ;
+ m_reverseKeyTranslateTable[PAD6 ] = KX_PAD6 ;
+ m_reverseKeyTranslateTable[PAD8 ] = KX_PAD8 ;
+
+ m_reverseKeyTranslateTable[PAD1 ] = KX_PAD1 ;
+ m_reverseKeyTranslateTable[PAD3 ] = KX_PAD3 ;
+ m_reverseKeyTranslateTable[PAD5 ] = KX_PAD5 ;
+ m_reverseKeyTranslateTable[PAD7 ] = KX_PAD7 ;
+ m_reverseKeyTranslateTable[PAD9 ] = KX_PAD9 ;
+
+ m_reverseKeyTranslateTable[PADPERIOD ] = KX_PADPERIOD ;
+ m_reverseKeyTranslateTable[PADSLASHKEY ] = KX_PADSLASHKEY ;
+ m_reverseKeyTranslateTable[PADASTERKEY ] = KX_PADASTERKEY ;
+
+
+ m_reverseKeyTranslateTable[PAD0 ] = KX_PAD0 ;
+ m_reverseKeyTranslateTable[PADMINUS ] = KX_PADMINUS ;
+ m_reverseKeyTranslateTable[PADENTER ] = KX_PADENTER ;
+ m_reverseKeyTranslateTable[PADPLUSKEY ] = KX_PADPLUSKEY ;
+
+
+ m_reverseKeyTranslateTable[F1KEY ] = KX_F1KEY ;
+ m_reverseKeyTranslateTable[F2KEY ] = KX_F2KEY ;
+ m_reverseKeyTranslateTable[F3KEY ] = KX_F3KEY ;
+ m_reverseKeyTranslateTable[F4KEY ] = KX_F4KEY ;
+ m_reverseKeyTranslateTable[F5KEY ] = KX_F5KEY ;
+ m_reverseKeyTranslateTable[F6KEY ] = KX_F6KEY ;
+ m_reverseKeyTranslateTable[F7KEY ] = KX_F7KEY ;
+ m_reverseKeyTranslateTable[F8KEY ] = KX_F8KEY ;
+ m_reverseKeyTranslateTable[F9KEY ] = KX_F9KEY ;
+ m_reverseKeyTranslateTable[F10KEY ] = KX_F10KEY ;
+ m_reverseKeyTranslateTable[F11KEY ] = KX_F11KEY ;
+ m_reverseKeyTranslateTable[F12KEY ] = KX_F12KEY ;
+
+ m_reverseKeyTranslateTable[PAUSEKEY ] = KX_PAUSEKEY ;
+ m_reverseKeyTranslateTable[INSERTKEY ] = KX_INSERTKEY ;
+ m_reverseKeyTranslateTable[HOMEKEY ] = KX_HOMEKEY ;
+ m_reverseKeyTranslateTable[PAGEUPKEY ] = KX_PAGEUPKEY ;
+ m_reverseKeyTranslateTable[PAGEDOWNKEY ] = KX_PAGEDOWNKEY ;
+ m_reverseKeyTranslateTable[ENDKEY ] = KX_ENDKEY ;
+
+
+ }
+
+ virtual ~BL_BlenderInputDevice()
+ {
+
+ }
+
+ KX_EnumInputs ToNative(unsigned short incode) {
+ return m_reverseKeyTranslateTable[incode];
+ }
+
+ virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode)=0;
+// virtual const SCA_InputEvent& GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode)=0;
+ virtual bool ConvertBlenderEvent(unsigned short incode,short val)=0;
+
+};
+#endif //__KX_BLENDERINPUTDEVICE
+
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp b/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp
new file mode 100644
index 00000000000..c6ae91ae282
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp
@@ -0,0 +1,172 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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
+// annoying warnings about truncated STL debug info
+#pragma warning (disable :4786)
+#endif
+
+#include "KX_BlenderKeyboardDevice.h"
+
+KX_BlenderKeyboardDevice::KX_BlenderKeyboardDevice()
+ : m_hookesc(false)
+{
+
+}
+KX_BlenderKeyboardDevice::~KX_BlenderKeyboardDevice()
+{
+
+}
+
+/**
+ IsPressed gives boolean information about keyboard status, true if pressed, false if not
+*/
+
+bool KX_BlenderKeyboardDevice::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode)
+{
+ const SCA_InputEvent & inevent = m_eventStatusTables[m_currentTable][inputcode];
+ bool pressed = (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED ||
+ inevent.m_status == SCA_InputEvent::KX_ACTIVE);
+ return pressed;
+}
+/*const SCA_InputEvent& KX_BlenderKeyboardDevice::GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode)
+{
+ return m_eventStatusTables[m_currentTable][inputcode];
+}
+*/
+/**
+ NextFrame toggles currentTable with previousTable,
+ and copy relevant event information from previous to current
+ (pressed keys need to be remembered)
+*/
+void KX_BlenderKeyboardDevice::NextFrame()
+{
+ SCA_IInputDevice::NextFrame();
+
+ // now convert justpressed keyevents into regular (active) keyevents
+ int previousTable = 1-m_currentTable;
+ for (int keyevent= KX_BEGINKEY; keyevent< KX_ENDKEY;keyevent++)
+ {
+ SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][keyevent];
+ if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED ||
+ oldevent.m_status == SCA_InputEvent::KX_ACTIVE )
+ {
+ m_eventStatusTables[m_currentTable][keyevent] = oldevent;
+ m_eventStatusTables[m_currentTable][keyevent].m_status = SCA_InputEvent::KX_ACTIVE;
+ }
+ }
+}
+
+/**
+ ConvertBlenderEvent translates blender keyboard events into ketsji kbd events
+ extra event information is stored, like ramp-mode (just released/pressed)
+*/
+
+
+bool KX_BlenderKeyboardDevice::ConvertBlenderEvent(unsigned short incode,short val)
+{
+ bool result = false;
+
+ // convert event
+ KX_EnumInputs kxevent = this->ToNative(incode);
+
+ // only process it, if it's a key
+ if (kxevent >= KX_BEGINKEY && kxevent < KX_ENDKEY)
+ {
+ int previousTable = 1-m_currentTable;
+
+ if (val > 0)
+ {
+ if (kxevent == KX_ESCKEY && val != 0 && !m_hookesc)
+ result = true;
+ if (kxevent == KX_PAUSEKEY && val && (IsPressed(KX_LEFTCTRLKEY) || IsPressed(KX_RIGHTCTRLKEY)))
+ result = true;
+
+ // todo: convert val ??
+ m_eventStatusTables[m_currentTable][kxevent].m_eventval = val ; //???
+
+ switch (m_eventStatusTables[previousTable][kxevent].m_status)
+ {
+ case SCA_InputEvent::KX_JUSTACTIVATED:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE;
+ break;
+ }
+ case SCA_InputEvent::KX_ACTIVE:
+
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE;
+ break;
+ }
+ case SCA_InputEvent::KX_NO_INPUTSTATUS:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED;
+ break;
+ }
+ default:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED;
+ }
+ }
+
+ } else
+ {
+ // blender eventval == 0
+ switch (m_eventStatusTables[previousTable][kxevent].m_status)
+ {
+ case SCA_InputEvent::KX_JUSTACTIVATED:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTRELEASED;
+ break;
+ }
+ case SCA_InputEvent::KX_ACTIVE:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTRELEASED;
+ break;
+ }
+ default:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+void KX_BlenderKeyboardDevice::HookEscape()
+{
+ m_hookesc = true;
+}
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.h b/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.h
new file mode 100644
index 00000000000..932751c37eb
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.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 __KX_BLENDERKEYBOARDDEVICE
+#define __KX_BLENDERKEYBOARDDEVICE
+
+#include "KX_BlenderInputDevice.h"
+
+class KX_BlenderKeyboardDevice : public BL_BlenderInputDevice
+{
+ bool m_hookesc;
+public:
+ KX_BlenderKeyboardDevice();
+ virtual ~KX_BlenderKeyboardDevice();
+
+ virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode);
+// virtual const SCA_InputEvent& GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode);
+ virtual bool ConvertBlenderEvent(unsigned short incode,short val);
+ virtual void NextFrame();
+ virtual void HookEscape();
+};
+
+#endif //__KX_BLENDERKEYBOARDDEVICE
+
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.cpp b/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.cpp
new file mode 100644
index 00000000000..92e0a6113bb
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.cpp
@@ -0,0 +1,180 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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
+// annoying warnings about truncated STL debug info
+#pragma warning (disable :4786)
+#endif
+
+#include "KX_BlenderMouseDevice.h"
+
+KX_BlenderMouseDevice::KX_BlenderMouseDevice()
+{
+
+}
+KX_BlenderMouseDevice::~KX_BlenderMouseDevice()
+{
+
+}
+
+/**
+ IsPressed gives boolean information about mouse status, true if pressed, false if not
+*/
+
+bool KX_BlenderMouseDevice::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode)
+{
+ const SCA_InputEvent & inevent = m_eventStatusTables[m_currentTable][inputcode];
+ bool pressed = (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED ||
+ inevent.m_status == SCA_InputEvent::KX_ACTIVE);
+ return pressed;
+}
+/*const SCA_InputEvent& KX_BlenderMouseDevice::GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode)
+{
+ return m_eventStatusTables[m_currentTable][inputcode];
+}
+*/
+
+/**
+ NextFrame toggles currentTable with previousTable,
+ and copy relevant event information from previous to current
+ (pressed keys need to be remembered)
+*/
+void KX_BlenderMouseDevice::NextFrame()
+{
+ SCA_IInputDevice::NextFrame();
+
+ // now convert justpressed keyevents into regular (active) keyevents
+ int previousTable = 1-m_currentTable;
+ for (int mouseevent= KX_BEGINMOUSE; mouseevent< KX_ENDMOUSEBUTTONS;mouseevent++)
+ {
+ SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][mouseevent];
+ if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED ||
+ oldevent.m_status == SCA_InputEvent::KX_ACTIVE )
+ {
+ m_eventStatusTables[m_currentTable][mouseevent] = oldevent;
+ m_eventStatusTables[m_currentTable][mouseevent].m_status = SCA_InputEvent::KX_ACTIVE;
+ }
+ }
+ for (int mousemove= KX_ENDMOUSEBUTTONS; mousemove< KX_ENDMOUSE;mousemove++)
+ {
+ SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][mousemove];
+ m_eventStatusTables[m_currentTable][mousemove] = oldevent;
+ if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED ||
+ oldevent.m_status == SCA_InputEvent::KX_ACTIVE )
+ {
+
+ m_eventStatusTables[m_currentTable][mousemove].m_status = SCA_InputEvent::KX_JUSTRELEASED;
+ } else
+ {
+ if (oldevent.m_status == SCA_InputEvent::KX_JUSTRELEASED)
+ {
+
+ m_eventStatusTables[m_currentTable][mousemove].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS ;
+ }
+ }
+ }
+}
+
+
+/**
+ ConvertBlenderEvent translates blender mouse events into ketsji kbd events
+ extra event information is stored, like ramp-mode (just released/pressed)
+*/
+
+
+bool KX_BlenderMouseDevice::ConvertBlenderEvent(unsigned short incode,short val)
+{
+ bool result = false;
+
+ // convert event
+ KX_EnumInputs kxevent = this->ToNative(incode);
+
+ // only process it, if it's a key
+ if (kxevent > KX_BEGINMOUSE && kxevent < KX_ENDMOUSE)
+ {
+ int previousTable = 1-m_currentTable;
+
+
+ if (val > 0)
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_eventval = val ; //???
+
+ switch (m_eventStatusTables[previousTable][kxevent].m_status)
+ {
+
+ case SCA_InputEvent::KX_ACTIVE:
+ case SCA_InputEvent::KX_JUSTACTIVATED:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE;
+ break;
+ }
+ case SCA_InputEvent::KX_JUSTRELEASED:
+ {
+ if ( kxevent > KX_BEGINMOUSEBUTTONS && kxevent < KX_ENDMOUSEBUTTONS)
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED;
+ } else
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE;
+
+ }
+ break;
+ }
+ default:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED;
+ }
+ }
+
+ } else
+ {
+ // blender eventval == 0
+ switch (m_eventStatusTables[previousTable][kxevent].m_status)
+ {
+ case SCA_InputEvent::KX_JUSTACTIVATED:
+ case SCA_InputEvent::KX_ACTIVE:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTRELEASED;
+ break;
+ }
+ default:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS;
+ }
+ }
+ }
+ }
+ return result;
+}
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.h b/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.h
new file mode 100644
index 00000000000..a4a1d27b2ee
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.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 __KX_BLENDERMOUSEDEVICE
+#define __KX_BLENDERMOUSEDEVICE
+
+#include "KX_BlenderInputDevice.h"
+
+class KX_BlenderMouseDevice : public BL_BlenderInputDevice
+{
+public:
+ KX_BlenderMouseDevice();
+ virtual ~KX_BlenderMouseDevice();
+
+ virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode);
+// virtual const SCA_InputEvent& GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode);
+ virtual bool ConvertBlenderEvent(unsigned short incode,short val);
+ virtual void NextFrame();
+};
+
+#endif //__KX_BLENDERMOUSEDEVICE
+
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.cpp b/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.cpp
new file mode 100644
index 00000000000..cdb6ce5b829
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.cpp
@@ -0,0 +1,117 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_BlenderPolyMaterial.h"
+#include "BKE_mesh.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#if 0
+KX_BlenderPolyMaterial::KX_BlenderPolyMaterial(const STR_String &texname,
+ bool ba,
+ const STR_String& matname,
+ int tile,
+ int tilexrep,
+ int tileyrep,
+ int mode,
+ bool transparant,
+ bool zsort,
+ int lightlayer,
+ bool bIsTriangle,
+ void* clientobject,
+ struct MTFace* tface)
+ : RAS_IPolyMaterial(texname,
+ false,
+ matname,
+ tile,
+ tilexrep,
+ tileyrep,
+ mode,
+ transparant,
+ zsort,
+ lightlayer,
+ bIsTriangle,
+ clientobject),
+ m_tface(tface)
+{
+}
+
+void KX_BlenderPolyMaterial::Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const
+{
+
+
+ if (GetCachingInfo() != cachingInfo)
+ {
+ if (!cachingInfo)
+ {
+ set_tpage(NULL);
+ }
+ cachingInfo = GetCachingInfo();
+
+ if ((m_drawingmode & 4)&& (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED))
+ {
+ update_realtime_texture((struct MTFace*) m_tface, rasty->GetTime());
+ set_tpage(m_tface);
+ rasty->EnableTextures(true);
+ }
+ else
+ {
+ set_tpage(NULL);
+ rasty->EnableTextures(false);
+ }
+
+ if(m_drawingmode & RAS_IRasterizer::KX_TWOSIDE)
+ {
+ rasty->SetCullFace(false);
+ }
+ else
+ {
+ rasty->SetCullFace(true);
+ }
+
+ if (m_drawingmode & RAS_IRasterizer::KX_LINES) {
+ rasty->SetLines(true);
+ }
+ else {
+ rasty->SetLines(false);
+ }
+ }
+
+ rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity);
+ rasty->SetShinyness(m_shininess);
+ rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0);
+}
+
+
+#endif
+
+
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.h b/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.h
new file mode 100644
index 00000000000..1dab77cb901
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.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 __KX_BLENDERPOLYMATERIAL
+#define __KX_BLENDERPOLYMATERIAL
+
+#include "RAS_MaterialBucket.h"
+#include "RAS_IRasterizer.h"
+
+struct MTFace;
+extern "C" int set_tpage(MTFace* tface); /* Worst hack ever */
+
+#if 0
+class KX_BlenderPolyMaterial : public RAS_IPolyMaterial
+{
+ /** Blender texture face structure. */
+ MTFace* m_tface;
+
+public:
+
+ KX_BlenderPolyMaterial(const STR_String &texname,
+ bool ba,
+ const STR_String& matname,
+ int tile,
+ int tilexrep,
+ int tileyrep,
+ int mode,
+ bool transparant,
+ bool zsort,
+ int lightlayer,
+ bool bIsTriangle,
+ void* clientobject,
+ struct MTFace* tface);
+
+ /**
+ * Returns the caching information for this material,
+ * This can be used to speed up the rasterizing process.
+ * @return The caching information.
+ */
+ virtual TCachingInfo GetCachingInfo(void) const;
+
+ /**
+ * Activates the material in the (OpenGL) rasterizer.
+ * On entry, the cachingInfo contains info about the last activated material.
+ * On exit, the cachingInfo should contain updated info about this material.
+ * @param rasty The rasterizer in which the material should be active.
+ * @param cachingInfo The information about the material used to speed up rasterizing.
+ */
+ virtual void Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const;
+
+ /**
+ * Returns the Blender texture face structure that is used for this material.
+ * @return The material's texture face.
+ */
+ MTFace* GetMTFace(void) const;
+protected:
+private:
+};
+
+
+inline MTFace* KX_BlenderPolyMaterial::GetMTFace(void) const
+{
+ return m_tface;
+}
+
+inline RAS_IPolyMaterial::TCachingInfo KX_BlenderPolyMaterial::GetCachingInfo(void) const
+{
+ return GetMTFace();
+}
+
+#endif
+
+#endif // __KX_BLENDERPOLYMATERIAL
+
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp
new file mode 100644
index 00000000000..463f06869d6
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp
@@ -0,0 +1,478 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_BlenderRenderTools.h"
+
+#ifdef WIN32
+// OpenGL gl.h needs 'windows.h' on windows platforms
+#include <windows.h>
+#endif //WIN32
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#else
+#include <GL/gl.h>
+#endif
+
+#include "RAS_IRenderTools.h"
+#include "RAS_IRasterizer.h"
+#include "RAS_LightObject.h"
+#include "RAS_ICanvas.h"
+#include "RAS_GLExtensionManager.h"
+
+// next two includes/dependencies come from the shadow feature
+// it needs the gameobject and the sumo physics scene for a raycast
+#include "KX_GameObject.h"
+
+#include "KX_BlenderPolyMaterial.h"
+#include "KX_PolygonMaterial.h"
+#include "KX_BlenderMaterial.h"
+
+#include "Value.h"
+
+#include "KX_BlenderGL.h" // for text printing
+#include "STR_String.h"
+#include "RAS_BucketManager.h" // for polymaterial (needed for textprinting)
+
+#include "KX_RayCast.h"
+#include "KX_IPhysicsController.h"
+#include "PHY_IPhysicsEnvironment.h"
+#include "KX_Scene.h"
+
+KX_BlenderRenderTools::KX_BlenderRenderTools()
+{
+ glGetIntegerv(GL_MAX_LIGHTS, (GLint*) &m_numgllights);
+ if (m_numgllights < 8)
+ m_numgllights = 8;
+}
+
+/**
+ProcessLighting performs lighting on objects. the layer is a bitfield that contains layer information.
+There are 20 'official' layers in blender.
+A light is applied on an object only when they are in the same layer.
+OpenGL has a maximum of 8 lights (simultaneous), so 20 * 8 lights are possible in a scene.
+*/
+
+int KX_BlenderRenderTools::ProcessLighting(int layer)
+{
+
+ int result = false;
+
+ if (layer < 0)
+ {
+ DisableOpenGLLights();
+ result = false;
+ } else
+ {
+ if (m_clientobject)
+ {
+ if (applyLights(layer))
+ {
+ EnableOpenGLLights();
+ result = true;
+ } else
+ {
+ DisableOpenGLLights();
+ result = false;
+ }
+ }
+ }
+ return result;
+
+
+}
+
+
+void KX_BlenderRenderTools::BeginFrame(RAS_IRasterizer* rasty)
+{
+ m_clientobject = NULL;
+ m_lastblenderobject = NULL;
+ m_lastblenderlights = false;
+ m_lastlayer = -1;
+ m_lastlighting = false;
+ m_modified = true;
+ DisableOpenGLLights();
+
+
+}
+
+bool KX_BlenderRenderTools::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data)
+{
+ double* const oglmatrix = (double* const) data;
+ MT_Point3 resultpoint(hit_point);
+ MT_Vector3 resultnormal(hit_normal);
+ MT_Vector3 left(oglmatrix[0],oglmatrix[1],oglmatrix[2]);
+ MT_Vector3 dir = -(left.cross(resultnormal)).safe_normalized();
+ left = (dir.cross(resultnormal)).safe_normalized();
+ // for the up vector, we take the 'resultnormal' returned by the physics
+
+ double maat[16]={
+ left[0], left[1], left[2], 0,
+ dir[0], dir[1], dir[2], 0,
+ resultnormal[0],resultnormal[1],resultnormal[2], 0,
+ 0, 0, 0, 1};
+ glTranslated(resultpoint[0],resultpoint[1],resultpoint[2]);
+ //glMultMatrixd(oglmatrix);
+ glMultMatrixd(maat);
+ return true;
+}
+
+void KX_BlenderRenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmatrix,int objectdrawmode )
+{
+ /* FIXME:
+ blender: intern/moto/include/MT_Vector3.inl:42: MT_Vector3 operator/(const
+ MT_Vector3&, double): Assertion `!MT_fuzzyZero(s)' failed.
+
+ Program received signal SIGABRT, Aborted.
+ [Switching to Thread 16384 (LWP 1519)]
+ 0x40477571 in kill () from /lib/libc.so.6
+ (gdb) bt
+ #7 0x08334368 in MT_Vector3::normalized() const ()
+ #8 0x0833e6ec in KX_BlenderRenderTools::applyTransform(RAS_IRasterizer*, double*, int) ()
+ */
+
+ if (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED ||
+ objectdrawmode & RAS_IPolyMaterial::BILLBOARD_AXISALIGNED)
+ {
+ // rotate the billboard/halo
+ //page 360/361 3D Game Engine Design, David Eberly for a discussion
+ // on screen aligned and axis aligned billboards
+ // assumed is that the preprocessor transformed all billboard polygons
+ // so that their normal points into the positive x direction (1.0 , 0.0 , 0.0)
+ // when new parenting for objects is done, this rotation
+ // will be moved into the object
+
+ MT_Point3 objpos (oglmatrix[12],oglmatrix[13],oglmatrix[14]);
+ MT_Point3 campos = rasty->GetCameraPosition();
+ MT_Vector3 dir = (campos - objpos).safe_normalized();
+ MT_Vector3 up(0,0,1.0);
+
+ KX_GameObject* gameobj = (KX_GameObject*) this->m_clientobject;
+ // get scaling of halo object
+ MT_Vector3 size = gameobj->GetSGNode()->GetLocalScale();
+
+ bool screenaligned = (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED)!=0;//false; //either screen or axisaligned
+ if (screenaligned)
+ {
+ up = (up - up.dot(dir) * dir).safe_normalized();
+ } else
+ {
+ dir = (dir - up.dot(dir)*up).safe_normalized();
+ }
+
+ MT_Vector3 left = dir.normalized();
+ dir = (left.cross(up)).normalized();
+
+ // we have calculated the row vectors, now we keep
+ // local scaling into account:
+
+ left *= size[0];
+ dir *= size[1];
+ up *= size[2];
+ double maat[16]={
+ left[0], left[1],left[2], 0,
+ dir[0], dir[1],dir[2],0,
+ up[0],up[1],up[2],0,
+ 0,0,0,1};
+ glTranslated(objpos[0],objpos[1],objpos[2]);
+ glMultMatrixd(maat);
+
+ } else
+ {
+ if (objectdrawmode & RAS_IPolyMaterial::SHADOW)
+ {
+ // shadow must be cast to the ground, physics system needed here!
+ MT_Point3 frompoint(oglmatrix[12],oglmatrix[13],oglmatrix[14]);
+ KX_GameObject *gameobj = (KX_GameObject*) this->m_clientobject;
+ MT_Vector3 direction = MT_Vector3(0,0,-1);
+
+ direction.normalize();
+ direction *= 100000;
+
+ MT_Point3 topoint = frompoint + direction;
+
+ KX_Scene* kxscene = (KX_Scene*) m_auxilaryClientInfo;
+ PHY_IPhysicsEnvironment* physics_environment = kxscene->GetPhysicsEnvironment();
+ KX_IPhysicsController* physics_controller = gameobj->GetPhysicsController();
+
+ KX_GameObject *parent = gameobj->GetParent();
+ if (!physics_controller && parent)
+ physics_controller = parent->GetPhysicsController();
+ if (parent)
+ parent->Release();
+
+ MT_Point3 resultpoint;
+ MT_Vector3 resultnormal;
+ if (!KX_RayCast::RayTest(physics_controller, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_BlenderRenderTools>(this, oglmatrix)))
+ {
+ // couldn't find something to cast the shadow on...
+ glMultMatrixd(oglmatrix);
+ }
+ } else
+ {
+
+ // 'normal' object
+ glMultMatrixd(oglmatrix);
+ }
+ }
+}
+
+
+/**
+Render Text renders text into a (series of) polygon, using a texture font,
+Each character consists of one polygon (one quad or two triangles)
+*/
+void KX_BlenderRenderTools::RenderText(int mode,RAS_IPolyMaterial* polymat,float v1[3],float v2[3],float v3[3],float v4[3])
+{
+
+ STR_String mytext = ((CValue*)m_clientobject)->GetPropertyText("Text");
+
+ const unsigned int flag = polymat->GetFlag();
+ struct MTFace* tface = 0;
+ unsigned int *col = 0;
+
+ if(flag & RAS_BLENDERMAT) {
+ KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(polymat);
+ tface = bl_mat->GetMTFace();
+ col = bl_mat->GetMCol();
+ } else {
+ KX_PolygonMaterial* blenderpoly = static_cast<KX_PolygonMaterial*>(polymat);
+ tface = blenderpoly->GetMTFace();
+ col = blenderpoly->GetMCol();
+ }
+
+ BL_RenderText( mode,mytext,mytext.Length(),tface,col,v1,v2,v3,v4);
+
+}
+
+
+
+KX_BlenderRenderTools::~KX_BlenderRenderTools()
+{
+};
+
+
+void KX_BlenderRenderTools::EndFrame(RAS_IRasterizer* rasty)
+{
+}
+
+
+
+void KX_BlenderRenderTools::DisableOpenGLLights()
+{
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+}
+
+
+void KX_BlenderRenderTools::EnableOpenGLLights()
+{
+ glEnable(GL_LIGHTING);
+
+ glEnable(GL_COLOR_MATERIAL);
+ glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, true);
+ if (bgl::QueryExtension(bgl::_GL_EXT_separate_specular_color) || bgl::QueryVersion(1, 2))
+ glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
+
+}
+
+
+/**
+ * Rendering text using 2D bitmap functionality.
+ */
+void KX_BlenderRenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode,
+ const char* text,
+ int xco,
+ int yco,
+ int width,
+ int height)
+{
+ switch (mode) {
+ case RAS_IRenderTools::RAS_TEXT_PADDED: {
+ STR_String tmpstr(text);
+ BL_print_gamedebug_line_padded(tmpstr.Ptr(),xco,yco,width,height);
+ break;
+ }
+ default: {
+ STR_String tmpstr(text);
+ BL_print_gamedebug_line(tmpstr.Ptr(),xco,yco,width,height);
+ }
+ }
+}
+
+
+
+void KX_BlenderRenderTools::PushMatrix()
+{
+ glPushMatrix();
+}
+
+void KX_BlenderRenderTools::PopMatrix()
+{
+ glPopMatrix();
+}
+
+
+
+int KX_BlenderRenderTools::applyLights(int objectlayer)
+{
+// taken from blender source, incompatibility between Blender Object / GameObject
+
+ unsigned int count;
+ float vec[4];
+
+ vec[3]= 1.0;
+
+ for(count=0; count<m_numgllights; count++)
+ glDisable((GLenum)(GL_LIGHT0+count));
+
+ //std::vector<struct RAS_LightObject*> m_lights;
+ std::vector<struct RAS_LightObject*>::iterator lit = m_lights.begin();
+
+ glPushMatrix();
+ glLoadMatrixf(m_viewmat);
+ for (lit = m_lights.begin(), count = 0; !(lit==m_lights.end()) && count < m_numgllights; ++lit)
+ {
+ RAS_LightObject* lightdata = (*lit);
+ if (lightdata->m_layer & objectlayer)
+ {
+ vec[0] = (*(lightdata->m_worldmatrix))(0,3);
+ vec[1] = (*(lightdata->m_worldmatrix))(1,3);
+ vec[2] = (*(lightdata->m_worldmatrix))(2,3);
+ vec[3] = 1;
+
+ if(lightdata->m_type==RAS_LightObject::LIGHT_SUN) {
+
+ vec[0] = (*(lightdata->m_worldmatrix))(0,2);
+ vec[1] = (*(lightdata->m_worldmatrix))(1,2);
+ vec[2] = (*(lightdata->m_worldmatrix))(2,2);
+ //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((GLenum)(GL_LIGHT0+count), GL_POSITION, vec);
+ }
+ else {
+ //vec[3]= 1.0;
+ glLightfv((GLenum)(GL_LIGHT0+count), GL_POSITION, vec);
+ glLightf((GLenum)(GL_LIGHT0+count), GL_CONSTANT_ATTENUATION, 1.0);
+ glLightf((GLenum)(GL_LIGHT0+count), GL_LINEAR_ATTENUATION, lightdata->m_att1/lightdata->m_distance);
+ // without this next line it looks backward compatible.
+ //attennuation still is acceptable
+ glLightf((GLenum)(GL_LIGHT0+count), GL_QUADRATIC_ATTENUATION, lightdata->m_att2/(lightdata->m_distance*lightdata->m_distance));
+
+ if(lightdata->m_type==RAS_LightObject::LIGHT_SPOT) {
+ vec[0] = -(*(lightdata->m_worldmatrix))(0,2);
+ vec[1] = -(*(lightdata->m_worldmatrix))(1,2);
+ vec[2] = -(*(lightdata->m_worldmatrix))(2,2);
+ //vec[0]= -base->object->obmat[2][0];
+ //vec[1]= -base->object->obmat[2][1];
+ //vec[2]= -base->object->obmat[2][2];
+ glLightfv((GLenum)(GL_LIGHT0+count), GL_SPOT_DIRECTION, vec);
+ glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_CUTOFF, lightdata->m_spotsize/2.0);
+ glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_EXPONENT, 128.0*lightdata->m_spotblend);
+ }
+ else glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_CUTOFF, 180.0);
+ }
+
+ if (lightdata->m_nodiffuse)
+ {
+ vec[0] = vec[1] = vec[2] = vec[3] = 0.0;
+ } else {
+ vec[0]= lightdata->m_energy*lightdata->m_red;
+ vec[1]= lightdata->m_energy*lightdata->m_green;
+ vec[2]= lightdata->m_energy*lightdata->m_blue;
+ vec[3]= 1.0;
+ }
+ glLightfv((GLenum)(GL_LIGHT0+count), GL_DIFFUSE, vec);
+ if (lightdata->m_nospecular)
+ {
+ vec[0] = vec[1] = vec[2] = vec[3] = 0.0;
+ } else if (lightdata->m_nodiffuse) {
+ vec[0]= lightdata->m_energy*lightdata->m_red;
+ vec[1]= lightdata->m_energy*lightdata->m_green;
+ vec[2]= lightdata->m_energy*lightdata->m_blue;
+ vec[3]= 1.0;
+ }
+ glLightfv((GLenum)(GL_LIGHT0+count), GL_SPECULAR, vec);
+ glEnable((GLenum)(GL_LIGHT0+count));
+
+ count++;
+
+ }
+ }
+ glPopMatrix();
+
+ return count;
+
+}
+
+
+
+RAS_IPolyMaterial* KX_BlenderRenderTools::CreateBlenderPolyMaterial(
+ const STR_String &texname,
+ bool ba,const STR_String& matname,int tile,int tilexrep,int tileyrep,int mode,bool transparant,bool zsort, int lightlayer
+ ,bool bIsTriangle,void* clientobject,void* tface)
+{
+ assert(!"Deprecated");
+/* return new KX_BlenderPolyMaterial(
+
+ texname,
+ ba,matname,tile,tilexrep,tileyrep,mode,transparant,zsort, lightlayer
+ ,bIsTriangle,clientobject,(struct MTFace*)tface);*/
+ return NULL;
+}
+
+void KX_BlenderRenderTools::MotionBlur(RAS_IRasterizer* rasterizer)
+{
+ int state = rasterizer->GetMotionBlurState();
+ float motionblurvalue;
+ if(state)
+ {
+ motionblurvalue = rasterizer->GetMotionBlurValue();
+ if(state==1)
+ {
+ //bugfix:load color buffer into accum buffer for the first time(state=1)
+ glAccum(GL_LOAD, 1.0);
+ rasterizer->SetMotionBlurState(2);
+ }
+ else if(motionblurvalue>=0.0 && motionblurvalue<=1.0)
+ {
+ glAccum(GL_MULT, motionblurvalue);
+ glAccum(GL_ACCUM, 1-motionblurvalue);
+ glAccum(GL_RETURN, 1.0);
+ glFlush();
+ }
+ }
+}
+
+unsigned int KX_BlenderRenderTools::m_numgllights;
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h
new file mode 100644
index 00000000000..a79302a283e
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h
@@ -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 *****
+ */
+#ifndef __KX_BLENDERRENDERTOOLS
+#define __KX_BLENDERRENDERTOOLS
+
+#ifdef WIN32
+// don't show stl-warnings
+#pragma warning (disable:4786)
+#endif
+
+#include "RAS_IRenderTools.h"
+
+struct KX_ClientObjectInfo;
+
+/**
+BlenderRenderTools are a set of tools to apply 2D/3D graphics effects, which are not
+part of the (polygon) Rasterizer.
+Effects like 2D text, 3D (polygon) text, lighting.
+*/
+
+class KX_BlenderRenderTools : public RAS_IRenderTools
+{
+ bool m_lastblenderlights;
+ void* m_lastblenderobject;
+ int m_lastlayer;
+ bool m_lastlighting;
+ static unsigned int m_numgllights;
+
+public:
+
+ KX_BlenderRenderTools();
+ virtual ~KX_BlenderRenderTools();
+
+ virtual void EndFrame(class RAS_IRasterizer* rasty);
+ virtual void BeginFrame(class RAS_IRasterizer* rasty);
+ void DisableOpenGLLights();
+ void EnableOpenGLLights();
+ int ProcessLighting(int layer);
+
+ virtual void RenderText2D(RAS_TEXT_RENDER_MODE mode,
+ const char* text,
+ int xco,
+ int yco,
+ int width,
+ int height);
+ virtual void RenderText(int mode,
+ class RAS_IPolyMaterial* polymat,
+ float v1[3],
+ float v2[3],
+ float v3[3],
+ float v4[3]);
+ void applyTransform(class RAS_IRasterizer* rasty,
+ double* oglmatrix,
+ int objectdrawmode );
+ int applyLights(int objectlayer);
+ virtual void PushMatrix();
+ virtual void PopMatrix();
+
+ virtual class RAS_IPolyMaterial* CreateBlenderPolyMaterial(const STR_String &texname,
+ bool ba,
+ const STR_String& matname,
+ int tile,
+ int tilexrep,
+ int tileyrep,
+ int mode,
+ bool transparant,
+ bool zsort,
+ int lightlayer,
+ bool bIsTriangle,
+ void* clientobject,
+ void* tface);
+
+ bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data);
+
+ virtual void MotionBlur(RAS_IRasterizer* rasterizer);
+};
+
+#endif //__KX_BLENDERRENDERTOOLS
+
+
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderSystem.cpp b/source/gameengine/BlenderRoutines/KX_BlenderSystem.cpp
new file mode 100644
index 00000000000..290f1d71777
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderSystem.cpp
@@ -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 *****
+ */
+
+#include "KX_ISystem.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#pragma warning (disable :4786)
+#include <windows.h>
+#endif //WIN32
+
+#include <iostream>
+#include <stdio.h>
+#include "KX_BlenderInputDevice.h"
+#include "KX_BlenderSystem.h"
+
+#include "PIL_time.h"
+
+KX_BlenderSystem::KX_BlenderSystem()
+: KX_ISystem()
+{
+ m_starttime = PIL_check_seconds_timer();
+}
+
+double KX_BlenderSystem::GetTimeInSeconds()
+{
+ return PIL_check_seconds_timer() - m_starttime;
+}
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderSystem.h b/source/gameengine/BlenderRoutines/KX_BlenderSystem.h
new file mode 100644
index 00000000000..829668b4192
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/KX_BlenderSystem.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 __KX_BLENDERSYSTEM
+#define __KX_BLENDERSYSTEM
+
+/**
+ * Blender System embedding. Needed when gameengine runs embedded within Blender.
+ */
+#include "KX_ISystem.h"
+
+class KX_BlenderSystem : public KX_ISystem
+{
+ double m_starttime;
+
+public:
+ KX_BlenderSystem();
+ virtual ~KX_BlenderSystem() {};
+ virtual double GetTimeInSeconds();
+};
+
+#endif //__KX_BLENDERSYSTEM
+
diff --git a/source/gameengine/BlenderRoutines/Makefile b/source/gameengine/BlenderRoutines/Makefile
new file mode 100644
index 00000000000..f0097e40807
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/Makefile
@@ -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 *****
+#
+#
+
+LIBNAME = bloutines
+DIR = $(OCGDIR)/gameengine/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_SUMO)/include -I$(NAN_SOLID)/include
+CPPFLAGS += -I$(NAN_SOLID)
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_BMFONT)/include
+CPPFLAGS += -I$(NAN_FUZZICS)/include
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include
+# because of kernel dependency on makesdna
+CPPFLAGS += -I../../blender/makesdna
+CPPFLAGS += -I../../blender/include
+# because of kernel dependency on imbuf
+CPPFLAGS += -I../../blender/imbuf
+CPPFLAGS += -I../../blender/blenlib
+CPPFLAGS += -I../../blender/blenkernel
+CPPFLAGS += -I../../blender/render/extern/include
+CPPFLAGS += -I../../blender/blenloader
+CPPFLAGS += -I../../blender/blenkernel
+CPPFLAGS += -I../Converter
+CPPFLAGS += -I../Expressions
+CPPFLAGS += -I../GameLogic
+CPPFLAGS += -I../Ketsji
+CPPFLAGS += -I../Rasterizer
+CPPFLAGS += -I../Rasterizer/RAS_OpenGLRasterizer
+CPPFLAGS += -I../SceneGraph
+CPPFLAGS += -I../../kernel/gen_system
+CPPFLAGS += -I../Network
+CPPFLAGS += -I../Network/LoopBackNetwork
+CPPFLAGS += -I../Physics/common
+CPPFLAGS += -I../Physics/Sumo
+
+ifeq ($(OS),windows)
+ CPPFLAGS += -I../../blender
+endif
+
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
diff --git a/source/gameengine/BlenderRoutines/SConscript b/source/gameengine/BlenderRoutines/SConscript
new file mode 100644
index 00000000000..984b700abd6
--- /dev/null
+++ b/source/gameengine/BlenderRoutines/SConscript
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('*.cpp')
+
+incs = '. #source/kernel/gen_system #intern/string #intern/guardedalloc'
+incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #intern/bmfont'
+incs += ' #source/gameengine/Converter #source/blender/imbuf'
+incs += ' #intern/ghost/include'
+incs += ' #intern/moto/include #source/gameengine/Ketsji #source/blender/blenlib'
+incs += ' #source/blender/blenkernel #source/blender #source/blender/include'
+incs += ' #source/blender/makesdna #source/gameengine/Rasterizer #source/gameengine/GameLogic'
+incs += ' #source/gameengine/Expressions #source/gameengine/Network'
+incs += ' #source/gameengine/SceneGraph #source/gameengine/Physics/common'
+incs += ' #source/gameengine/Physics/Bullet #source/gameengine/Physics/Sumo'
+incs += ' #source/gameengine/Physics/Sumo/Fuzzics/include #source/gameengine/Network/LoopBackNetwork'
+incs += ' #intern/SoundSystem #source/blender/misc #source/blender/blenloader'
+
+incs += ' ' + env['BF_PYTHON_INC']
+incs += ' ' + env['BF_SOLID_INC']
+incs += ' ' + env['BF_BULLET_INC']
+incs += ' ' + env['BF_OPENGL_INC']
+
+cxxflags = []
+if env['OURPLATFORM']=='win32-vc':
+ cxxflags.append ('/GR')
+
+env.BlenderLib ( 'bf_bloutines', sources, Split(incs), [], libtype=['game', 'game2', 'player'], priority=[0, 0, 55] , compileflags=cxxflags)
diff --git a/source/gameengine/CMakeLists.txt b/source/gameengine/CMakeLists.txt
new file mode 100644
index 00000000000..b42d1d70e43
--- /dev/null
+++ b/source/gameengine/CMakeLists.txt
@@ -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) 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(
+ BlenderRoutines
+ Converter
+ Expressions
+ GameLogic
+ Ketsji
+ Ketsji/KXNetwork
+ Network
+ Network/LoopBackNetwork
+ Physics/common
+ Physics/Dummy
+ Rasterizer
+ Rasterizer/RAS_OpenGLRasterizer
+ SceneGraph
+ Physics/Bullet
+ Physics/Sumo
+)
+
+IF(WITH_PLAYER)
+ SUBDIRS(GamePlayer)
+ENDIF(WITH_PLAYER)
diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp
new file mode 100644
index 00000000000..b38599685af
--- /dev/null
+++ b/source/gameengine/Converter/BL_ActionActuator.cpp
@@ -0,0 +1,907 @@
+/**
+* $Id$
+*
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#if defined (__sgi)
+#include <math.h>
+#else
+#include <cmath>
+#endif
+
+#include "SCA_LogicManager.h"
+#include "BL_ActionActuator.h"
+#include "BL_ArmatureObject.h"
+#include "BL_SkinDeformer.h"
+#include "KX_GameObject.h"
+#include "STR_HashedString.h"
+#include "DNA_action_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_actuator_types.h"
+#include "BKE_action.h"
+#include "DNA_armature_types.h"
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "MT_Matrix4x4.h"
+#include "BKE_utildefines.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+BL_ActionActuator::~BL_ActionActuator()
+{
+
+ if (m_pose) {
+ free_pose_channels(m_pose);
+ MEM_freeN(m_pose);
+ m_pose = NULL;
+ };
+
+ if (m_userpose){
+ free_pose_channels(m_userpose);
+ MEM_freeN(m_userpose);
+ m_userpose=NULL;
+ }
+ if (m_blendpose) {
+ free_pose_channels(m_blendpose);
+ MEM_freeN(m_blendpose);
+ m_blendpose = NULL;
+ };
+
+}
+
+void BL_ActionActuator::ProcessReplica(){
+// bPose *oldpose = m_pose;
+// bPose *oldbpose = m_blendpose;
+
+ m_pose = NULL;
+ m_blendpose = NULL;
+ m_localtime=m_startframe;
+ m_lastUpdate=-1;
+
+}
+
+void BL_ActionActuator::SetBlendTime (float newtime){
+ m_blendframe = newtime;
+}
+
+CValue* BL_ActionActuator::GetReplica() {
+ BL_ActionActuator* replica = new BL_ActionActuator(*this);//m_float,GetName());
+ replica->ProcessReplica();
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+}
+
+bool BL_ActionActuator::ClampLocalTime()
+{
+ if (m_startframe < m_endframe)
+ {
+ if (m_localtime < m_startframe)
+ {
+ m_localtime = m_startframe;
+ return true;
+ }
+ else if (m_localtime > m_endframe)
+ {
+ m_localtime = m_endframe;
+ return true;
+ }
+ } else {
+ if (m_localtime > m_startframe)
+ {
+ m_localtime = m_startframe;
+ return true;
+ }
+ else if (m_localtime < m_endframe)
+ {
+ m_localtime = m_endframe;
+ return true;
+ }
+ }
+ return false;
+}
+
+void BL_ActionActuator::SetStartTime(float curtime)
+{
+ float direction = m_startframe < m_endframe ? 1.0 : -1.0;
+
+ if (!(m_flag & ACT_FLAG_REVERSE))
+ m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_FIXED_FRAME_PER_SEC;
+ else
+ m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_FIXED_FRAME_PER_SEC;
+}
+
+void BL_ActionActuator::SetLocalTime(float curtime)
+{
+ float delta_time = (curtime - m_starttime)*KX_FIXED_FRAME_PER_SEC;
+
+ if (m_endframe < m_startframe)
+ delta_time = -delta_time;
+
+ if (!(m_flag & ACT_FLAG_REVERSE))
+ m_localtime = m_startframe + delta_time;
+ else
+ m_localtime = m_endframe - delta_time;
+}
+
+
+bool BL_ActionActuator::Update(double curtime, bool frame)
+{
+ bool bNegativeEvent = false;
+ bool bPositiveEvent = false;
+ bool keepgoing = true;
+ bool wrap = false;
+ bool apply=true;
+ int priority;
+ float newweight;
+
+ // result = true if animation has to be continued, false if animation stops
+ // maybe there are events for us in the queue !
+ if (frame)
+ {
+ for (vector<CValue*>::iterator i=m_events.begin(); !(i==m_events.end());i++)
+ {
+ if ((*i)->GetNumber() == 0.0f)
+ bNegativeEvent = true;
+ else
+ bPositiveEvent= true;
+ (*i)->Release();
+
+ }
+ m_events.clear();
+
+ if (bPositiveEvent)
+ m_flag |= ACT_FLAG_ACTIVE;
+
+ if (bNegativeEvent)
+ {
+ if (!(m_flag & ACT_FLAG_ACTIVE))
+ return false;
+ m_flag &= ~ACT_FLAG_ACTIVE;
+ }
+ }
+
+ /* We know that action actuators have been discarded from all non armature objects:
+ if we're being called, we're attached to a BL_ArmatureObject */
+ BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent();
+ float length = m_endframe - m_startframe;
+
+ priority = m_priority;
+
+ /* Determine pre-incrementation behaviour and set appropriate flags */
+ switch (m_playtype){
+ case ACT_ACTION_MOTION:
+ if (bNegativeEvent){
+ keepgoing=false;
+ apply=false;
+ };
+ break;
+ case ACT_ACTION_FROM_PROP:
+ if (bNegativeEvent){
+ apply=false;
+ keepgoing=false;
+ }
+ break;
+ case ACT_ACTION_LOOP_END:
+ if (bPositiveEvent){
+ if (!(m_flag & ACT_FLAG_LOCKINPUT)){
+ m_flag &= ~ACT_FLAG_KEYUP;
+ m_flag &= ~ACT_FLAG_REVERSE;
+ m_flag |= ACT_FLAG_LOCKINPUT;
+ m_localtime = m_startframe;
+ m_starttime = curtime;
+ }
+ }
+ if (bNegativeEvent){
+ m_flag |= ACT_FLAG_KEYUP;
+ }
+ break;
+ case ACT_ACTION_LOOP_STOP:
+ if (bPositiveEvent){
+ if (!(m_flag & ACT_FLAG_LOCKINPUT)){
+ m_flag &= ~ACT_FLAG_REVERSE;
+ m_flag &= ~ACT_FLAG_KEYUP;
+ m_flag |= ACT_FLAG_LOCKINPUT;
+ SetStartTime(curtime);
+ }
+ }
+ if (bNegativeEvent){
+ m_flag |= ACT_FLAG_KEYUP;
+ m_flag &= ~ACT_FLAG_LOCKINPUT;
+ keepgoing=false;
+ apply=false;
+ }
+ break;
+ case ACT_ACTION_FLIPPER:
+ if (bPositiveEvent){
+ if (!(m_flag & ACT_FLAG_LOCKINPUT)){
+ m_flag &= ~ACT_FLAG_REVERSE;
+ m_flag |= ACT_FLAG_LOCKINPUT;
+ SetStartTime(curtime);
+ }
+ }
+ else if (bNegativeEvent){
+ m_flag |= ACT_FLAG_REVERSE;
+ m_flag &= ~ACT_FLAG_LOCKINPUT;
+ SetStartTime(curtime);
+ }
+ break;
+ case ACT_ACTION_PLAY:
+ if (bPositiveEvent){
+ if (!(m_flag & ACT_FLAG_LOCKINPUT)){
+ m_flag &= ~ACT_FLAG_REVERSE;
+ m_localtime = m_starttime;
+ m_starttime = curtime;
+ m_flag |= ACT_FLAG_LOCKINPUT;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Perform increment */
+ if (keepgoing){
+ if (m_playtype == ACT_ACTION_MOTION){
+ MT_Point3 newpos;
+ MT_Point3 deltapos;
+
+ newpos = obj->NodeGetWorldPosition();
+
+ /* Find displacement */
+ deltapos = newpos-m_lastpos;
+ m_localtime += (length/m_stridelength) * deltapos.length();
+ m_lastpos = newpos;
+ }
+ else{
+ SetLocalTime(curtime);
+ }
+ }
+
+ /* Check if a wrapping response is needed */
+ if (length){
+ if (m_localtime < m_startframe || m_localtime > m_endframe)
+ {
+ m_localtime = m_startframe + fmod(m_localtime, length);
+ wrap = true;
+ }
+ }
+ else
+ m_localtime = m_startframe;
+
+ /* Perform post-increment tasks */
+ switch (m_playtype){
+ case ACT_ACTION_FROM_PROP:
+ {
+ CValue* propval = GetParent()->GetProperty(m_propname);
+ if (propval)
+ m_localtime = propval->GetNumber();
+
+ if (bNegativeEvent){
+ keepgoing=false;
+ }
+ }
+ break;
+ case ACT_ACTION_MOTION:
+ break;
+ case ACT_ACTION_LOOP_STOP:
+ break;
+ case ACT_ACTION_FLIPPER:
+ if (wrap){
+ if (!(m_flag & ACT_FLAG_REVERSE)){
+ m_localtime=m_endframe;
+ //keepgoing = false;
+ }
+ else {
+ m_localtime=m_startframe;
+ keepgoing = false;
+ }
+ }
+ break;
+ case ACT_ACTION_LOOP_END:
+ if (wrap){
+ if (m_flag & ACT_FLAG_KEYUP){
+ keepgoing = false;
+ m_localtime = m_endframe;
+ m_flag &= ~ACT_FLAG_LOCKINPUT;
+ }
+ SetStartTime(curtime);
+ }
+ break;
+ case ACT_ACTION_PLAY:
+ if (wrap){
+ m_localtime = m_endframe;
+ keepgoing = false;
+ m_flag &= ~ACT_FLAG_LOCKINPUT;
+ }
+ break;
+ default:
+ keepgoing = false;
+ break;
+ }
+
+
+ if (bNegativeEvent)
+ m_blendframe=0.0;
+
+ /* Apply the pose if necessary*/
+ if (apply){
+
+ /* Priority test */
+ if (obj->SetActiveAction(this, priority, curtime)){
+
+ /* Get the underlying pose from the armature */
+ obj->GetPose(&m_pose);
+
+ /* Override the necessary channels with ones from the action */
+ extract_pose_from_action(m_pose, m_action, m_localtime);
+
+ /* Perform the user override (if any) */
+ if (m_userpose){
+ extract_pose_from_pose(m_pose, m_userpose);
+// clear_pose(m_userpose);
+ MEM_freeN(m_userpose);
+ m_userpose = NULL;
+ }
+#if 1
+ /* Handle blending */
+ if (m_blendin && (m_blendframe<m_blendin)){
+ /* If this is the start of a blending sequence... */
+ if ((m_blendframe==0.0) || (!m_blendpose)){
+ obj->GetMRDPose(&m_blendpose);
+ m_blendstart = curtime;
+ }
+
+ /* Find percentages */
+ newweight = (m_blendframe/(float)m_blendin);
+ blend_poses(m_pose, m_blendpose, 1.0 - newweight, ACTSTRIPMODE_BLEND);
+
+ /* Increment current blending percentage */
+ m_blendframe = (curtime - m_blendstart)*KX_FIXED_FRAME_PER_SEC;
+ if (m_blendframe>m_blendin)
+ m_blendframe = m_blendin;
+
+ }
+#endif
+ m_lastUpdate = m_localtime;
+ obj->SetPose (m_pose);
+ }
+ else{
+ m_blendframe = 0.0;
+ }
+ }
+
+ if (!keepgoing){
+ m_blendframe = 0.0;
+ }
+ return keepgoing;
+};
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+
+PyTypeObject BL_ActionActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "BL_ActionActuator",
+ sizeof(BL_ActionActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject BL_ActionActuator::Parents[] = {
+ &BL_ActionActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef BL_ActionActuator::Methods[] = {
+ {"setAction", (PyCFunction) BL_ActionActuator::sPySetAction, METH_VARARGS, SetAction_doc},
+ {"setStart", (PyCFunction) BL_ActionActuator::sPySetStart, METH_VARARGS, SetStart_doc},
+ {"setEnd", (PyCFunction) BL_ActionActuator::sPySetEnd, METH_VARARGS, SetEnd_doc},
+ {"setBlendin", (PyCFunction) BL_ActionActuator::sPySetBlendin, METH_VARARGS, SetBlendin_doc},
+ {"setPriority", (PyCFunction) BL_ActionActuator::sPySetPriority, METH_VARARGS, SetPriority_doc},
+ {"setFrame", (PyCFunction) BL_ActionActuator::sPySetFrame, METH_VARARGS, SetFrame_doc},
+ {"setProperty", (PyCFunction) BL_ActionActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
+ {"setBlendtime", (PyCFunction) BL_ActionActuator::sPySetBlendtime, METH_VARARGS, SetBlendtime_doc},
+
+ {"getAction", (PyCFunction) BL_ActionActuator::sPyGetAction, METH_VARARGS, GetAction_doc},
+ {"getStart", (PyCFunction) BL_ActionActuator::sPyGetStart, METH_VARARGS, GetStart_doc},
+ {"getEnd", (PyCFunction) BL_ActionActuator::sPyGetEnd, METH_VARARGS, GetEnd_doc},
+ {"getBlendin", (PyCFunction) BL_ActionActuator::sPyGetBlendin, METH_VARARGS, GetBlendin_doc},
+ {"getPriority", (PyCFunction) BL_ActionActuator::sPyGetPriority, METH_VARARGS, GetPriority_doc},
+ {"getFrame", (PyCFunction) BL_ActionActuator::sPyGetFrame, METH_VARARGS, GetFrame_doc},
+ {"getProperty", (PyCFunction) BL_ActionActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
+ {"setChannel", (PyCFunction) BL_ActionActuator::sPySetChannel, METH_VARARGS, SetChannel_doc},
+// {"getChannel", (PyCFunction) BL_ActionActuator::sPyGetChannel, METH_VARARGS},
+ {"getType", (PyCFunction) BL_ActionActuator::sPyGetType, METH_VARARGS, GetType_doc},
+ {"setType", (PyCFunction) BL_ActionActuator::sPySetType, METH_VARARGS, SetType_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* BL_ActionActuator::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IActuator);
+}
+
+/* setStart */
+char BL_ActionActuator::GetAction_doc[] =
+"getAction()\n"
+"\tReturns a string containing the name of the current action.\n";
+
+PyObject* BL_ActionActuator::PyGetAction(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ if (m_action){
+ result = Py_BuildValue("s", m_action->id.name+2);
+ }
+ else{
+ Py_INCREF(Py_None);
+ result = Py_None;
+ }
+
+ return result;
+}
+
+/* getProperty */
+char BL_ActionActuator::GetProperty_doc[] =
+"getProperty()\n"
+"\tReturns the name of the property to be used in FromProp mode.\n";
+
+PyObject* BL_ActionActuator::PyGetProperty(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("s", (const char *)m_propname);
+
+ return result;
+}
+
+/* getFrame */
+char BL_ActionActuator::GetFrame_doc[] =
+"getFrame()\n"
+"\tReturns the current frame number.\n";
+
+PyObject* BL_ActionActuator::PyGetFrame(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("f", m_localtime);
+
+ return result;
+}
+
+/* getEnd */
+char BL_ActionActuator::GetEnd_doc[] =
+"getEnd()\n"
+"\tReturns the last frame of the action.\n";
+
+PyObject* BL_ActionActuator::PyGetEnd(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("f", m_endframe);
+
+ return result;
+}
+
+/* getStart */
+char BL_ActionActuator::GetStart_doc[] =
+"getStart()\n"
+"\tReturns the starting frame of the action.\n";
+
+PyObject* BL_ActionActuator::PyGetStart(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("f", m_startframe);
+
+ return result;
+}
+
+/* getBlendin */
+char BL_ActionActuator::GetBlendin_doc[] =
+"getBlendin()\n"
+"\tReturns the number of interpolation animation frames to be\n"
+"\tgenerated when this actuator is triggered.\n";
+
+PyObject* BL_ActionActuator::PyGetBlendin(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("f", m_blendin);
+
+ return result;
+}
+
+/* getPriority */
+char BL_ActionActuator::GetPriority_doc[] =
+"getPriority()\n"
+"\tReturns the priority for this actuator. Actuators with lower\n"
+"\tPriority numbers will override actuators with higher numbers.\n";
+
+PyObject* BL_ActionActuator::PyGetPriority(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("i", m_priority);
+
+ return result;
+}
+
+/* setAction */
+char BL_ActionActuator::SetAction_doc[] =
+"setAction(action, (reset))\n"
+"\t - action : The name of the action to set as the current action.\n"
+"\t - reset : Optional parameter indicating whether to reset the\n"
+"\t blend timer or not. A value of 1 indicates that the\n"
+"\t timer should be reset. A value of 0 will leave it\n"
+"\t unchanged. If reset is not specified, the timer will"
+"\t be reset.\n";
+
+PyObject* BL_ActionActuator::PySetAction(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ char *string;
+ int reset = 1;
+
+ if (PyArg_ParseTuple(args,"s|i",&string, &reset))
+ {
+ bAction *action;
+
+ action = (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(STR_String(string));
+
+ if (!action){
+ /* NOTE! Throw an exception or something */
+ // printf ("setAction failed: Action not found\n", string);
+ }
+ else{
+ m_action=action;
+ if (reset)
+ m_blendframe = 0;
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setStart */
+char BL_ActionActuator::SetStart_doc[] =
+"setStart(start)\n"
+"\t - start : Specifies the starting frame of the animation.\n";
+
+PyObject* BL_ActionActuator::PySetStart(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float start;
+
+ if (PyArg_ParseTuple(args,"f",&start))
+ {
+ m_startframe = start;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setEnd */
+char BL_ActionActuator::SetEnd_doc[] =
+"setEnd(end)\n"
+"\t - end : Specifies the ending frame of the animation.\n";
+
+PyObject* BL_ActionActuator::PySetEnd(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float end;
+
+ if (PyArg_ParseTuple(args,"f",&end))
+ {
+ m_endframe = end;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setBlendin */
+char BL_ActionActuator::SetBlendin_doc[] =
+"setBlendin(blendin)\n"
+"\t - blendin : Specifies the number of frames of animation to generate\n"
+"\t when making transitions between actions.\n";
+
+PyObject* BL_ActionActuator::PySetBlendin(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float blendin;
+
+ if (PyArg_ParseTuple(args,"f",&blendin))
+ {
+ m_blendin = blendin;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setBlendtime */
+char BL_ActionActuator::SetBlendtime_doc[] =
+"setBlendtime(blendtime)\n"
+"\t - blendtime : Allows the script to directly modify the internal timer\n"
+"\t used when generating transitions between actions. This\n"
+"\t parameter must be in the range from 0.0 to 1.0.\n";
+
+PyObject* BL_ActionActuator::PySetBlendtime(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float blendframe;
+
+ if (PyArg_ParseTuple(args,"f",&blendframe))
+ {
+ m_blendframe = blendframe * m_blendin;
+ if (m_blendframe<0)
+ m_blendframe = 0;
+ if (m_blendframe>m_blendin)
+ m_blendframe = m_blendin;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setPriority */
+char BL_ActionActuator::SetPriority_doc[] =
+"setPriority(priority)\n"
+"\t - priority : Specifies the new priority. Actuators will lower\n"
+"\t priority numbers will override actuators with higher\n"
+"\t numbers.\n";
+
+PyObject* BL_ActionActuator::PySetPriority(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int priority;
+
+ if (PyArg_ParseTuple(args,"i",&priority))
+ {
+ m_priority = priority;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setFrame */
+char BL_ActionActuator::SetFrame_doc[] =
+"setFrame(frame)\n"
+"\t - frame : Specifies the new current frame for the animation\n";
+
+PyObject* BL_ActionActuator::PySetFrame(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float frame;
+
+ if (PyArg_ParseTuple(args,"f",&frame))
+ {
+ m_localtime = frame;
+ if (m_localtime<m_startframe)
+ m_localtime=m_startframe;
+ else if (m_localtime>m_endframe)
+ m_localtime=m_endframe;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setProperty */
+char BL_ActionActuator::SetProperty_doc[] =
+"setProperty(prop)\n"
+"\t - prop : A string specifying the property name to be used in\n"
+"\t FromProp playback mode.\n";
+
+PyObject* BL_ActionActuator::PySetProperty(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ char *string;
+
+ if (PyArg_ParseTuple(args,"s",&string))
+ {
+ m_propname = string;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/*
+PyObject* BL_ActionActuator::PyGetChannel(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ char *string;
+
+ if (PyArg_ParseTuple(args,"s",&string))
+ {
+ m_propname = string;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+*/
+
+/* setChannel */
+char BL_ActionActuator::SetChannel_doc[] =
+"setChannel(channel, matrix)\n"
+"\t - channel : A string specifying the name of the bone channel.\n"
+"\t - matrix : A 4x4 matrix specifying the overriding transformation\n"
+"\t as an offset from the bone's rest position.\n";
+
+PyObject* BL_ActionActuator::PySetChannel(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float matrix[4][4];
+ char *string;
+ PyObject* pylist;
+ bool error = false;
+ int row,col;
+ int mode = 0; /* 0 for bone space, 1 for armature/world space */
+
+ PyArg_ParseTuple(args,"sO|i", &string, &pylist, &mode);
+
+ if (pylist->ob_type == &CListValue::Type)
+ {
+ CListValue* listval = (CListValue*) pylist;
+ if (listval->GetCount() == 4)
+ {
+ for (row=0;row<4;row++) // each row has a 4-vector [x,y,z, w]
+ {
+ CListValue* vecval = (CListValue*)listval->GetValue(row);
+ for (col=0;col<4;col++)
+ {
+ matrix[row][col] = vecval->GetValue(col)->GetNumber();
+
+ }
+ }
+ }
+ else
+ {
+ error = true;
+ }
+ }
+ else
+ {
+ // assert the list is long enough...
+ int numitems = PyList_Size(pylist);
+ if (numitems == 4)
+ {
+ for (row=0;row<4;row++) // each row has a 4-vector [x,y,z, w]
+ {
+
+ PyObject* veclist = PyList_GetItem(pylist,row); // here we have a vector4 list
+ for (col=0;col<4;col++)
+ {
+ matrix[row][col] = PyFloat_AsDouble(PyList_GetItem(veclist,col));
+
+ }
+ }
+ }
+ else
+ {
+ error = true;
+ }
+ }
+
+ if (!error)
+ {
+
+/* DO IT HERE */
+ bPoseChannel *pchan= verify_pose_channel(m_userpose, string);
+
+ Mat4ToQuat(matrix, pchan->quat);
+ Mat4ToSize(matrix, pchan->size);
+ VECCOPY (pchan->loc, matrix[3]);
+
+ pchan->flag |= POSE_ROT|POSE_LOC|POSE_SIZE;
+
+ if (!m_userpose){
+ m_userpose = (bPose*)MEM_callocN(sizeof(bPose), "userPose");
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* getType */
+char BL_ActionActuator::GetType_doc[] =
+"getType()\n"
+"\tReturns the operation mode of the actuator.\n";
+PyObject* BL_ActionActuator::PyGetType(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return Py_BuildValue("h", m_playtype);
+}
+
+/* setType */
+char BL_ActionActuator::SetType_doc[] =
+"setType(mode)\n"
+"\t - mode: Play (0), Flipper (2), LoopStop (3), LoopEnd (4) or Property (6)\n"
+"\tSet the operation mode of the actuator.\n";
+PyObject* BL_ActionActuator::PySetType(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ short typeArg;
+
+ if (!PyArg_ParseTuple(args, "h", &typeArg)) {
+ return NULL;
+ }
+
+ switch (typeArg) {
+ case KX_ACT_ACTION_PLAY:
+ case KX_ACT_ACTION_FLIPPER:
+ case KX_ACT_ACTION_LOOPSTOP:
+ case KX_ACT_ACTION_LOOPEND:
+ case KX_ACT_ACTION_PROPERTY:
+ m_playtype = typeArg;
+ break;
+ default:
+ printf("Invalid type for action actuator: %d\n", typeArg); /* error */
+ }
+
+ Py_Return;
+}
+
diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h
new file mode 100644
index 00000000000..f96855408b7
--- /dev/null
+++ b/source/gameengine/Converter/BL_ActionActuator.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BL_ACTIONACTUATOR
+#define BL_ACTIONACTUATOR
+
+#include "GEN_HashedPtr.h"
+#include "SCA_IActuator.h"
+#include "MT_Point3.h"
+
+class BL_ActionActuator : public SCA_IActuator
+{
+public:
+ Py_Header;
+ BL_ActionActuator(SCA_IObject* gameobj,
+ const STR_String& propname,
+ float starttime,
+ float endtime,
+ struct bAction *action,
+ short playtype,
+ short blendin,
+ short priority,
+ float stride,
+ PyTypeObject* T=&Type)
+ : SCA_IActuator(gameobj,T),
+
+ m_lastpos(0, 0, 0),
+ m_blendframe(0),
+ m_flag(0),
+ m_startframe (starttime),
+ m_endframe(endtime) ,
+ m_starttime(0),
+ m_localtime(starttime),
+ m_lastUpdate(-1),
+ m_blendin(blendin),
+ m_blendstart(0),
+ m_stridelength(stride),
+ m_playtype(playtype),
+ m_priority(priority),
+ m_pose(NULL),
+ m_blendpose(NULL),
+ m_userpose(NULL),
+ m_action(action),
+ m_propname(propname)
+ {
+ };
+ virtual ~BL_ActionActuator();
+ virtual bool Update(double curtime, bool frame);
+ virtual CValue* GetReplica();
+ virtual void ProcessReplica();
+
+ void SetBlendTime (float newtime);
+
+ KX_PYMETHOD_DOC(BL_ActionActuator,SetAction);
+ KX_PYMETHOD_DOC(BL_ActionActuator,SetBlendin);
+ KX_PYMETHOD_DOC(BL_ActionActuator,SetPriority);
+ KX_PYMETHOD_DOC(BL_ActionActuator,SetStart);
+ KX_PYMETHOD_DOC(BL_ActionActuator,SetEnd);
+ KX_PYMETHOD_DOC(BL_ActionActuator,SetFrame);
+ KX_PYMETHOD_DOC(BL_ActionActuator,SetProperty);
+ KX_PYMETHOD_DOC(BL_ActionActuator,SetBlendtime);
+ KX_PYMETHOD_DOC(BL_ActionActuator,SetChannel);
+
+ KX_PYMETHOD_DOC(BL_ActionActuator,GetAction);
+ KX_PYMETHOD_DOC(BL_ActionActuator,GetBlendin);
+ KX_PYMETHOD_DOC(BL_ActionActuator,GetPriority);
+ KX_PYMETHOD_DOC(BL_ActionActuator,GetStart);
+ KX_PYMETHOD_DOC(BL_ActionActuator,GetEnd);
+ KX_PYMETHOD_DOC(BL_ActionActuator,GetFrame);
+ KX_PYMETHOD_DOC(BL_ActionActuator,GetProperty);
+// KX_PYMETHOD(BL_ActionActuator,GetChannel);
+ KX_PYMETHOD_DOC(BL_ActionActuator,GetType);
+ KX_PYMETHOD_DOC(BL_ActionActuator,SetType);
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ enum ActionActType
+ {
+ KX_ACT_ACTION_PLAY = 0,
+ KX_ACT_ACTION_FLIPPER = 2,
+ KX_ACT_ACTION_LOOPSTOP,
+ KX_ACT_ACTION_LOOPEND,
+ KX_ACT_ACTION_PROPERTY = 6
+ };
+
+protected:
+
+ void SetStartTime(float curtime);
+ void SetLocalTime(float curtime);
+ bool ClampLocalTime();
+
+ MT_Point3 m_lastpos;
+ float m_blendframe;
+ int m_flag;
+ /** The frame this action starts */
+ float m_startframe;
+ /** The frame this action ends */
+ float m_endframe;
+ /** The time this action started */
+ float m_starttime;
+ /** The current time of the action */
+ float m_localtime;
+
+ float m_lastUpdate;
+ float m_blendin;
+ float m_blendstart;
+ float m_stridelength;
+ short m_playtype;
+ short m_priority;
+ struct bPose* m_pose;
+ struct bPose* m_blendpose;
+ struct bPose* m_userpose;
+ struct bAction *m_action;
+ STR_String m_propname;
+};
+
+enum {
+ ACT_FLAG_REVERSE = 0x00000001,
+ ACT_FLAG_LOCKINPUT = 0x00000002,
+ ACT_FLAG_KEYUP = 0x00000004,
+ ACT_FLAG_ACTIVE = 0x00000008
+};
+
+#endif
+
diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp
new file mode 100644
index 00000000000..4bf13a09fb4
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureObject.cpp
@@ -0,0 +1,207 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "BL_ArmatureObject.h"
+#include "BL_ActionActuator.h"
+#include "BLI_blenlib.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "GEN_Map.h"
+#include "GEN_HashedPtr.h"
+#include "MEM_guardedalloc.h"
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+
+#include "MT_Matrix4x4.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+BL_ArmatureObject::BL_ArmatureObject(
+ void* sgReplicationInfo,
+ SG_Callbacks callbacks,
+ Object *armature )
+
+: KX_GameObject(sgReplicationInfo,callbacks),
+ m_objArma(armature),
+ m_mrdPose(NULL),
+ m_lastframe(0.),
+ m_activeAct(NULL),
+ m_activePriority(999)
+{
+ m_armature = get_armature(m_objArma);
+ m_pose = m_objArma->pose;
+}
+
+
+CValue* BL_ArmatureObject::GetReplica()
+{
+ BL_ArmatureObject* replica = new BL_ArmatureObject(*this);
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ ProcessReplica(replica);
+ return replica;
+}
+
+void BL_ArmatureObject::ProcessReplica(BL_ArmatureObject *replica)
+{
+ KX_GameObject::ProcessReplica(replica);
+
+}
+
+BL_ArmatureObject::~BL_ArmatureObject()
+{
+ if (m_mrdPose){
+ free_pose_channels(m_mrdPose);
+ MEM_freeN(m_mrdPose);
+ }
+}
+
+/* note, you can only call this for exisiting Armature objects, and not mix it with other Armatures */
+/* there is only 1 unique Pose per Armature */
+void BL_ArmatureObject::ApplyPose()
+{
+ if (m_pose){
+ // copy to armature object
+ extract_pose_from_pose(m_objArma->pose, m_pose);
+
+ // is this needed anymore?
+ //if (!m_mrdPose)
+ // copy_pose (&m_mrdPose, m_pose, 0);
+ //else
+ // extract_pose_from_pose(m_mrdPose, m_pose);
+ }
+}
+
+void BL_ArmatureObject::SetPose(bPose *pose)
+{
+ m_pose = pose;
+}
+
+bool BL_ArmatureObject::SetActiveAction(BL_ActionActuator *act, short priority, double curtime)
+{
+ if (curtime != m_lastframe){
+ m_activePriority = 9999;
+ m_lastframe= curtime;
+ m_activeAct = NULL;
+ }
+
+ if (priority<=m_activePriority)
+ {
+ if (m_activeAct && (m_activeAct!=act))
+ m_activeAct->SetBlendTime(0.0); /* Reset the blend timer */
+ m_activeAct = act;
+ m_activePriority = priority;
+ m_lastframe = curtime;
+
+ return true;
+ }
+ else{
+ act->SetBlendTime(0.0);
+ return false;
+ }
+
+}
+
+BL_ActionActuator * BL_ArmatureObject::GetActiveAction()
+{
+ return m_activeAct;
+}
+
+void BL_ArmatureObject::GetPose(bPose **pose)
+{
+ /* If the caller supplies a null pose, create a new one. */
+ /* Otherwise, copy the armature's pose channels into the caller-supplied pose */
+
+ if (!*pose) {
+ /* probably not to good of an idea to
+ duplicate everying, but it clears up
+ a crash and memory leakage when
+ &BL_ActionActuator::m_pose is freed
+ */
+ int copy_constraint_channels_hack = 1;
+ copy_pose(pose, m_pose, copy_constraint_channels_hack);
+ }
+ else
+ extract_pose_from_pose(*pose, m_pose);
+
+}
+
+void BL_ArmatureObject::GetMRDPose(bPose **pose)
+{
+ /* If the caller supplies a null pose, create a new one. */
+ /* Otherwise, copy the armature's pose channels into the caller-supplied pose */
+
+ // is this needed anymore?
+ //if (!m_mrdPose){
+ // copy_pose (&m_mrdPose, m_pose, 0);
+ //}
+
+ if (!*pose)
+ copy_pose(pose, m_objArma->pose, 0);
+ else
+ extract_pose_from_pose(*pose, m_objArma->pose);
+
+}
+
+short BL_ArmatureObject::GetActivePriority()
+{
+ return m_activePriority;
+}
+
+double BL_ArmatureObject::GetLastFrame()
+{
+ return m_lastframe;
+}
+
+bool BL_ArmatureObject::GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix) const
+{
+ Object* par_arma = m_objArma;
+ where_is_pose(par_arma);
+ bPoseChannel *pchan= get_pose_channel(par_arma->pose, bone->name);
+
+ if(pchan) {
+ matrix.setValue(&pchan->pose_mat[0][0]);
+ return true;
+ }
+ return false;
+}
+
+float BL_ArmatureObject::GetBoneLength(Bone* bone) const
+{
+ return (float)(MT_Point3(bone->head) - MT_Point3(bone->tail)).length();
+}
diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h
new file mode 100644
index 00000000000..aafc8271dd6
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureObject.h
@@ -0,0 +1,92 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 BL_ARMATUREOBJECT
+#define BL_ARMATUREOBJECT
+
+#include "KX_GameObject.h"
+
+#include "SG_IObject.h"
+
+struct bArmature;
+struct Bone;
+class BL_ActionActuator;
+class MT_Matrix4x4;
+struct Object;
+
+class BL_ArmatureObject : public KX_GameObject
+{
+public:
+ double GetLastFrame ();
+ short GetActivePriority();
+ virtual void ProcessReplica(BL_ArmatureObject *replica);
+ class BL_ActionActuator * GetActiveAction();
+
+ BL_ArmatureObject(
+ void* sgReplicationInfo,
+ SG_Callbacks callbacks,
+ Object *armature
+ );
+ virtual ~BL_ArmatureObject();
+
+ virtual CValue* GetReplica();
+ void GetMRDPose(struct bPose **pose);
+ void GetPose(struct bPose **pose);
+ void SetPose (struct bPose *pose);
+ void ApplyPose();
+ bool SetActiveAction(class BL_ActionActuator *act, short priority, double curtime);
+
+ struct bArmature * GetArmature() { return m_armature; }
+ const struct bArmature * GetArmature() const { return m_armature; }
+
+ Object* GetArmatureObject() {return m_objArma;}
+
+ /// Retrieve the pose matrix for the specified bone.
+ /// Returns true on success.
+ bool GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix) const;
+
+ /// Returns the bone length. The end of the bone is in the local y direction.
+ float GetBoneLength(Bone* bone) const;
+
+ virtual int GetGameObjectType() { return OBJ_ARMATURE; }
+protected:
+ Object *m_objArma;
+ struct bArmature *m_armature;
+ struct bPose *m_pose;
+ struct bPose *m_mrdPose;
+ double m_lastframe;
+ class BL_ActionActuator *m_activeAct;
+ short m_activePriority;
+};
+
+#endif
+
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
new file mode 100644
index 00000000000..fde54025fc7
--- /dev/null
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -0,0 +1,2270 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Convert blender data to ketsji
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif
+
+#include <math.h>
+
+#include "BL_BlenderDataConversion.h"
+#include "KX_BlenderGL.h"
+#include "KX_BlenderScalarInterpolator.h"
+
+#include "RAS_IPolygonMaterial.h"
+#include "KX_PolygonMaterial.h"
+
+// Expressions
+#include "ListValue.h"
+#include "IntValue.h"
+// Collision & Fuzzics LTD
+
+#include "PHY_Pro.h"
+
+
+#include "KX_Scene.h"
+#include "KX_GameObject.h"
+#include "RAS_FramingManager.h"
+#include "RAS_MeshObject.h"
+
+#include "KX_ConvertActuators.h"
+#include "KX_ConvertControllers.h"
+#include "KX_ConvertSensors.h"
+
+#include "SCA_LogicManager.h"
+#include "SCA_EventManager.h"
+#include "SCA_TimeEventManager.h"
+#include "KX_Light.h"
+#include "KX_Camera.h"
+#include "KX_EmptyObject.h"
+#include "MT_Point3.h"
+#include "MT_Transform.h"
+#include "MT_MinMax.h"
+#include "SCA_IInputDevice.h"
+#include "RAS_TexMatrix.h"
+#include "RAS_ICanvas.h"
+#include "RAS_MaterialBucket.h"
+//#include "KX_BlenderPolyMaterial.h"
+#include "RAS_Polygon.h"
+#include "RAS_TexVert.h"
+#include "RAS_BucketManager.h"
+#include "RAS_IRenderTools.h"
+#include "BL_Material.h"
+#include "KX_BlenderMaterial.h"
+#include "BL_Texture.h"
+
+#include "DNA_action_types.h"
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BL_SkinMeshObject.h"
+#include "BL_SkinDeformer.h"
+#include "BL_MeshDeformer.h"
+//#include "BL_ArmatureController.h"
+
+#include "BlenderWorldInfo.h"
+
+#include "KX_KetsjiEngine.h"
+#include "KX_BlenderSceneConverter.h"
+
+#include"SND_Scene.h"
+#include "SND_SoundListener.h"
+
+/* This little block needed for linking to Blender... */
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+/* This list includes only data type definitions */
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_group_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_property_types.h"
+#include "DNA_text_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_actuator_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_key_types.h"
+#include "DNA_armature_types.h"
+
+#include "MEM_guardedalloc.h"
+#include "BKE_utildefines.h"
+#include "BKE_key.h"
+#include "BKE_mesh.h"
+#include "MT_Point3.h"
+
+extern "C" {
+ #include "BKE_customdata.h"
+}
+
+#include "BKE_material.h" /* give_current_material */
+/* end of blender include block */
+
+#include "KX_BlenderInputDevice.h"
+#include "KX_ConvertProperties.h"
+#include "KX_HashedPtr.h"
+
+
+#include "KX_ScalarInterpolator.h"
+
+#include "KX_IpoConvert.h"
+#include "SYS_System.h"
+
+#include "SG_Node.h"
+#include "SG_BBox.h"
+#include "SG_Tree.h"
+
+// defines USE_ODE to choose physics engine
+#include "KX_ConvertPhysicsObject.h"
+
+
+// This file defines relationships between parents and children
+// in the game engine.
+
+#include "KX_SG_NodeRelationships.h"
+#include "KX_SG_BoneParentNodeRelationship.h"
+
+#include "BL_ArmatureObject.h"
+#include "BL_DeformableGameObject.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "BSE_headerbuttons.h"
+void update_for_newframe();
+//void scene_update_for_newframe(struct Scene *sce, unsigned int lay);
+//#include "BKE_ipo.h"
+//void do_all_data_ipos(void);
+#ifdef __cplusplus
+}
+#endif
+
+static int default_face_mode = TF_DYNAMIC;
+
+static unsigned int KX_rgbaint2uint_new(unsigned int icol)
+{
+ union
+ {
+ unsigned int integer;
+ unsigned char cp[4];
+ } out_color, in_color;
+
+ in_color.integer = icol;
+ out_color.cp[0] = in_color.cp[3]; // red
+ out_color.cp[1] = in_color.cp[2]; // green
+ out_color.cp[2] = in_color.cp[1]; // blue
+ out_color.cp[3] = in_color.cp[0]; // alpha
+
+ return out_color.integer;
+}
+
+/* Now the real converting starts... */
+static unsigned int KX_Mcol2uint_new(MCol col)
+{
+ /* color has to be converted without endian sensitivity. So no shifting! */
+ union
+ {
+ MCol col;
+ unsigned int integer;
+ unsigned char cp[4];
+ } out_color, in_color;
+
+ in_color.col = col;
+ out_color.cp[0] = in_color.cp[3]; // red
+ out_color.cp[1] = in_color.cp[2]; // green
+ out_color.cp[2] = in_color.cp[1]; // blue
+ out_color.cp[3] = in_color.cp[0]; // alpha
+
+ return out_color.integer;
+}
+
+static void SetDefaultFaceType(Scene* scene)
+{
+ default_face_mode = TF_DYNAMIC;
+ Base *base = static_cast<Base*>(scene->base.first);
+ while(base)
+ {
+ if (base->object->type == OB_LAMP)
+ {
+ default_face_mode = TF_DYNAMIC|TF_LIGHT;
+ return;
+ }
+ base = base->next;
+ }
+}
+
+
+// --
+static void GetRGB(short type,
+ MFace* mface,
+ MCol* mmcol,
+ Material *mat,
+ unsigned int &c0,
+ unsigned int &c1,
+ unsigned int &c2,
+ unsigned int &c3)
+{
+ unsigned int color = 0xFFFFFFFFL;
+ switch(type)
+ {
+ case 0: // vertex colors
+ {
+ if(mmcol) {
+ c0 = KX_Mcol2uint_new(mmcol[0]);
+ c1 = KX_Mcol2uint_new(mmcol[1]);
+ c2 = KX_Mcol2uint_new(mmcol[2]);
+ if (mface->v4)
+ c3 = KX_Mcol2uint_new(mmcol[3]);
+ }else // backup white
+ {
+ c0 = KX_rgbaint2uint_new(color);
+ c1 = KX_rgbaint2uint_new(color);
+ c2 = KX_rgbaint2uint_new(color);
+ if (mface->v4)
+ c3 = KX_rgbaint2uint_new( color );
+ }
+ } break;
+
+
+ case 1: // material rgba
+ {
+ if (mat) {
+ union {
+ unsigned char cp[4];
+ unsigned int integer;
+ } col_converter;
+ col_converter.cp[3] = (unsigned char) (mat->r*255.0);
+ col_converter.cp[2] = (unsigned char) (mat->g*255.0);
+ col_converter.cp[1] = (unsigned char) (mat->b*255.0);
+ col_converter.cp[0] = (unsigned char) (mat->alpha*255.0);
+ color = col_converter.integer;
+ }
+ c0 = KX_rgbaint2uint_new(color);
+ c1 = KX_rgbaint2uint_new(color);
+ c2 = KX_rgbaint2uint_new(color);
+ if (mface->v4)
+ c3 = KX_rgbaint2uint_new(color);
+ } break;
+
+ default: // white
+ {
+ c0 = KX_rgbaint2uint_new(color);
+ c1 = KX_rgbaint2uint_new(color);
+ c2 = KX_rgbaint2uint_new(color);
+ if (mface->v4)
+ c3 = KX_rgbaint2uint_new(color);
+ } break;
+ }
+}
+
+typedef struct MTF_localLayer
+{
+ MTFace *face;
+ char *name;
+}MTF_localLayer;
+
+// ------------------------------------
+BL_Material* ConvertMaterial(
+ Mesh* mesh,
+ Material *mat,
+ MTFace* tface,
+ MFace* mface,
+ MCol* mmcol,
+ int lightlayer,
+ Object* blenderobj,
+ MTF_localLayer *layers)
+{
+ //this needs some type of manager
+ BL_Material *material = new BL_Material();
+
+ int numchan = -1;
+ bool validmat = (mat!=0);
+ bool validface = (mesh->mtface && tface);
+
+ short type = 0;
+ if( validmat )
+ type = 1; // material color
+
+ material->IdMode = DEFAULT_BLENDER;
+
+ // --------------------------------
+ if(validmat) {
+
+ // use vertex colors by explicitly setting
+ if(mat->mode &MA_VERTEXCOLP)
+ type = 0;
+
+ // use lighting?
+ material->ras_mode |= ( mat->mode & MA_SHLESS )?0:USE_LIGHT;
+ MTex *mttmp = 0;
+ numchan = getNumTexChannels(mat);
+ int valid_index = 0;
+
+ // use the face texture if
+ // 1) it is set in the buttons
+ // 2) we have a face texture and a material but no valid texture in slot 1
+ bool facetex = false;
+ if(validface && mat->mode &MA_FACETEXTURE)
+ facetex = true;
+ if(validface && !mat->mtex[0])
+ facetex = true;
+ if(validface && mat->mtex[0]) {
+ MTex *tmp = mat->mtex[0];
+ if(!tmp->tex || tmp->tex && !tmp->tex->ima )
+ facetex = true;
+ }
+ numchan = numchan>MAXTEX?MAXTEX:numchan;
+
+ // foreach MTex
+ for(int i=0; i<numchan; i++) {
+ // use face tex
+
+ if(i==0 && facetex ) {
+ Image*tmp = (Image*)(tface->tpage);
+ if(tmp) {
+ material->img[i] = tmp;
+ material->texname[i] = material->img[i]->id.name;
+ material->flag[i] |= ( tface->transp &TF_ALPHA )?USEALPHA:0;
+ material->flag[i] |= ( tface->transp &TF_ADD )?CALCALPHA:0;
+ material->ras_mode|= ( tface->transp &(TF_ADD | TF_ALPHA))?TRANSP:0;
+ if(material->img[i]->flag & IMA_REFLECT)
+ material->mapping[i].mapping |= USEREFL;
+ else
+ {
+ mttmp = getImageFromMaterial( mat, i );
+ if(mttmp && mttmp->texco &TEXCO_UV)
+ {
+ STR_String uvName = mttmp->uvname;
+
+ if (!uvName.IsEmpty())
+ material->mapping[i].uvCoName = mttmp->uvname;
+ else
+ material->mapping[i].uvCoName = "";
+ }
+ material->mapping[i].mapping |= USEUV;
+ }
+
+ if(material->ras_mode & USE_LIGHT)
+ material->ras_mode &= ~USE_LIGHT;
+ if(tface->mode & TF_LIGHT)
+ material->ras_mode |= USE_LIGHT;
+
+ valid_index++;
+ }
+ else {
+ material->img[i] = 0;
+ material->texname[i] = "";
+ }
+ continue;
+ }
+
+ mttmp = getImageFromMaterial( mat, i );
+ if( mttmp ) {
+ if( mttmp->tex ) {
+ if( mttmp->tex->type == TEX_IMAGE ) {
+ material->mtexname[i] = mttmp->tex->id.name;
+ material->img[i] = mttmp->tex->ima;
+ if( material->img[i] ) {
+
+ material->texname[i] = material->img[i]->id.name;
+ material->flag[i] |= ( mttmp->tex->imaflag &TEX_MIPMAP )?MIPMAP:0;
+ // -----------------------
+ if( mttmp->tex->imaflag &TEX_USEALPHA ) {
+ material->flag[i] |= USEALPHA;
+ }
+ // -----------------------
+ else if( mttmp->tex->imaflag &TEX_CALCALPHA ) {
+ material->flag[i] |= CALCALPHA;
+ }
+ else if(mttmp->tex->flag &TEX_NEGALPHA) {
+ material->flag[i] |= USENEGALPHA;
+ }
+
+ material->color_blend[i] = mttmp->colfac;
+ material->flag[i] |= ( mttmp->mapto & MAP_ALPHA )?TEXALPHA:0;
+ material->flag[i] |= ( mttmp->texflag& MTEX_NEGATIVE )?TEXNEG:0;
+
+ }
+ }
+ else if(mttmp->tex->type == TEX_ENVMAP) {
+ if( mttmp->tex->env->stype == ENV_LOAD ) {
+
+ material->mtexname[i] = mttmp->tex->id.name;
+ EnvMap *env = mttmp->tex->env;
+ env->ima = mttmp->tex->ima;
+ material->cubemap[i] = env;
+
+ if (material->cubemap[i])
+ {
+ if (!material->cubemap[i]->cube[0])
+ BL_Texture::SplitEnvMap(material->cubemap[i]);
+
+ material->texname[i]= material->cubemap[i]->ima->id.name;
+ material->mapping[i].mapping |= USEENV;
+ }
+ }
+ }
+ material->flag[i] |= (mat->ipo!=0)?HASIPO:0;
+ /// --------------------------------
+ // mapping methods
+ material->mapping[i].mapping |= ( mttmp->texco & TEXCO_REFL )?USEREFL:0;
+
+ if(mttmp->texco & TEXCO_OBJECT) {
+ material->mapping[i].mapping |= USEOBJ;
+ if(mttmp->object)
+ material->mapping[i].objconame = mttmp->object->id.name;
+ }
+ else if(mttmp->texco &TEXCO_REFL)
+ material->mapping[i].mapping |= USEREFL;
+ else if(mttmp->texco &(TEXCO_ORCO|TEXCO_GLOB))
+ material->mapping[i].mapping |= USEORCO;
+ else if(mttmp->texco &TEXCO_UV)
+ {
+ STR_String uvName = mttmp->uvname;
+
+ if (!uvName.IsEmpty())
+ material->mapping[i].uvCoName = mttmp->uvname;
+ else
+ material->mapping[i].uvCoName = "";
+ material->mapping[i].mapping |= USEUV;
+ }
+ else if(mttmp->texco &TEXCO_NORM)
+ material->mapping[i].mapping |= USENORM;
+ else if(mttmp->texco &TEXCO_TANGENT)
+ material->mapping[i].mapping |= USETANG;
+ else
+ material->mapping[i].mapping |= DISABLE;
+
+ material->mapping[i].scale[0] = mttmp->size[0];
+ material->mapping[i].scale[1] = mttmp->size[1];
+ material->mapping[i].scale[2] = mttmp->size[2];
+ material->mapping[i].offsets[0] = mttmp->ofs[0];
+ material->mapping[i].offsets[1] = mttmp->ofs[1];
+ material->mapping[i].offsets[2] = mttmp->ofs[2];
+
+ material->mapping[i].projplane[0] = mttmp->projx;
+ material->mapping[i].projplane[1] = mttmp->projy;
+ material->mapping[i].projplane[2] = mttmp->projz;
+ /// --------------------------------
+
+ switch( mttmp->blendtype ) {
+ case MTEX_BLEND:
+ material->blend_mode[i] = BLEND_MIX;
+ break;
+ case MTEX_MUL:
+ material->blend_mode[i] = BLEND_MUL;
+ break;
+ case MTEX_ADD:
+ material->blend_mode[i] = BLEND_ADD;
+ break;
+ case MTEX_SUB:
+ material->blend_mode[i] = BLEND_SUB;
+ break;
+ case MTEX_SCREEN:
+ material->blend_mode[i] = BLEND_SCR;
+ break;
+ }
+ valid_index++;
+ }
+ }
+ }
+ // above one tex the switches here
+ // are not used
+ switch(valid_index) {
+ case 0:
+ material->IdMode = DEFAULT_BLENDER;
+ break;
+ case 1:
+ material->IdMode = ONETEX;
+ break;
+ default:
+ material->IdMode = GREATERTHAN2;
+ break;
+ }
+ material->SetUsers(mat->id.us);
+
+ material->num_enabled = valid_index;
+
+ material->speccolor[0] = mat->specr;
+ material->speccolor[1] = mat->specg;
+ material->speccolor[2] = mat->specb;
+ material->hard = (float)mat->har/4.0f;
+ material->matcolor[0] = mat->r;
+ material->matcolor[1] = mat->g;
+ material->matcolor[2] = mat->b;
+ material->matcolor[3] = mat->alpha;
+ material->alpha = mat->alpha;
+ material->emit = mat->emit;
+ material->spec_f = mat->spec;
+ material->ref = mat->ref;
+ material->amb = mat->amb;
+
+ // set alpha testing without z-sorting
+ if( ( validface && (!tface->transp)) && mat->mode & MA_ZTRA) {
+ // sets the RAS_IPolyMaterial::m_flag |RAS_FORCEALPHA
+ // this is so we don't have the overhead of the z-sorting code
+ material->ras_mode|=ALPHA_TEST;
+ }
+ else{
+ // use regular z-sorting
+ material->ras_mode |= ((mat->mode & MA_ZTRA) != 0)?ZSORT:0;
+ }
+ material->ras_mode |= ((mat->mode & MA_WIRE) != 0)?WIRE:0;
+ }
+ else {
+ int valid = 0;
+ // check for tface tex to fallback on
+ if( validface ){
+
+ // no light bugfix
+ if(tface->mode) material->ras_mode |= USE_LIGHT;
+
+ material->img[0] = (Image*)(tface->tpage);
+ // ------------------------
+ if(material->img[0]) {
+ material->texname[0] = material->img[0]->id.name;
+ material->mapping[0].mapping |= ( (material->img[0]->flag & IMA_REFLECT)!=0 )?USEREFL:0;
+ material->flag[0] |= ( tface->transp &TF_ALPHA )?USEALPHA:0;
+ material->flag[0] |= ( tface->transp &TF_ADD )?CALCALPHA:0;
+ material->ras_mode|= ( tface->transp & (TF_ADD|TF_ALPHA))?TRANSP:0;
+ valid++;
+ }
+ }
+ material->SetUsers(-1);
+ material->num_enabled = valid;
+ material->IdMode = TEXFACE;
+ material->speccolor[0] = 1.f;
+ material->speccolor[1] = 1.f;
+ material->speccolor[2] = 1.f;
+ material->hard = 35.f;
+ material->matcolor[0] = 0.5f;
+ material->matcolor[1] = 0.5f;
+ material->matcolor[2] = 0.5f;
+ material->spec_f = 0.5f;
+ material->ref = 0.8f;
+ }
+ MT_Point2 uv[4];
+ MT_Point2 uv2[4];
+
+ if( validface ) {
+
+ material->ras_mode |= !(
+ (mface->flag & ME_HIDE) ||
+ (tface->mode & TF_INVISIBLE)
+ )?POLY_VIS:0;
+
+ material->ras_mode |= ( (tface->mode & TF_DYNAMIC)!= 0 )?COLLIDER:0;
+ material->transp = tface->transp;
+
+ if(tface->transp)
+ material->ras_mode |= TRANSP;
+
+ material->tile = tface->tile;
+ material->mode = tface->mode;
+
+ uv[0] = MT_Point2(tface->uv[0]);
+ uv[1] = MT_Point2(tface->uv[1]);
+ uv[2] = MT_Point2(tface->uv[2]);
+
+ if (mface->v4)
+ uv[3] = MT_Point2(tface->uv[3]);
+ }
+ else {
+ // nothing at all
+ material->ras_mode |= (COLLIDER|POLY_VIS| (validmat?0:USE_LIGHT));
+ material->mode = default_face_mode;
+ material->transp = TF_SOLID;
+ material->tile = 0;
+ }
+
+
+
+ // get uv sets
+ if(validmat)
+ {
+ bool isFirstSet = true;
+
+ // only two sets implemented, but any of the eight
+ // sets can make up the two layers
+ for (int vind = 0; vind<material->num_enabled; vind++)
+ {
+ BL_Mapping &map = material->mapping[vind];
+ if (map.uvCoName.IsEmpty())
+ isFirstSet = false;
+ else
+ {
+ MT_Point2 uvSet[4];
+ for (int lay=0; lay<MAX_MTFACE; lay++)
+ {
+ MTF_localLayer& layer = layers[lay];
+ if (layer.face == 0) break;
+
+
+ bool processed = false;
+ if (strcmp(map.uvCoName.ReadPtr(), layer.name)==0)
+ {
+ uvSet[0] = MT_Point2(layer.face->uv[0]);
+ uvSet[1] = MT_Point2(layer.face->uv[1]);
+ uvSet[2] = MT_Point2(layer.face->uv[2]);
+
+ if (mface->v4)
+ uvSet[3] = MT_Point2(layer.face->uv[3]);
+
+ processed = true;
+ }
+
+ if (!processed) continue;
+
+ if (isFirstSet)
+ {
+ uv[0] = uvSet[0]; uv[1] = uvSet[1];
+ uv[2] = uvSet[2]; uv[3] = uvSet[3];
+ isFirstSet = false;
+ }
+ else
+ {
+ uv2[0] = uvSet[0]; uv2[1] = uvSet[1];
+ uv2[2] = uvSet[2]; uv2[3] = uvSet[3];
+ map.mapping |= USECUSTOMUV;
+ }
+ }
+ }
+ }
+ }
+
+ unsigned int rgb[4];
+ GetRGB(type,mface,mmcol,mat,rgb[0],rgb[1],rgb[2], rgb[3]);
+
+ // swap the material color, so MCol on TF_BMFONT works
+ if (validmat && type==1 && (tface && tface->mode & TF_BMFONT))
+ {
+ rgb[0] = KX_rgbaint2uint_new(rgb[0]);
+ rgb[1] = KX_rgbaint2uint_new(rgb[1]);
+ rgb[2] = KX_rgbaint2uint_new(rgb[2]);
+ rgb[3] = KX_rgbaint2uint_new(rgb[3]);
+ }
+
+ material->SetConversionRGB(rgb);
+ material->SetConversionUV(uv);
+ material->SetConversionUV2(uv2);
+
+
+ material->ras_mode |= (mface->v4==0)?TRIANGLE:0;
+ if(validmat)
+ material->matname =(mat->id.name);
+
+ material->tface = tface;
+ material->material = mat;
+ return material;
+}
+
+
+static void BL_ComputeTriTangentSpace(const MT_Vector3 &v1, const MT_Vector3 &v2, const MT_Vector3 &v3,
+ const MT_Vector2 &uv1, const MT_Vector2 &uv2, const MT_Vector2 &uv3,
+ MFace* mface, MT_Vector3 *tan1, MT_Vector3 *tan2)
+{
+ MT_Vector3 dx1(v2 - v1), dx2(v3 - v1);
+ MT_Vector2 duv1(uv2 - uv1), duv2(uv3 - uv1);
+
+ MT_Scalar r = 1.0 / (duv1.x() * duv2.y() - duv2.x() * duv1.y());
+ duv1 *= r;
+ duv2 *= r;
+ MT_Vector3 sdir(duv2.y() * dx1 - duv1.y() * dx2);
+ MT_Vector3 tdir(duv1.x() * dx2 - duv2.x() * dx1);
+
+ tan1[mface->v1] += sdir;
+ tan1[mface->v2] += sdir;
+ tan1[mface->v3] += sdir;
+
+ tan2[mface->v1] += tdir;
+ tan2[mface->v2] += tdir;
+ tan2[mface->v3] += tdir;
+}
+
+static MT_Vector4* BL_ComputeMeshTangentSpace(Mesh* mesh)
+{
+ MFace* mface = static_cast<MFace*>(mesh->mface);
+ MTFace* tface = static_cast<MTFace*>(mesh->mtface);
+
+ MT_Vector3 *tan1 = new MT_Vector3[mesh->totvert];
+ MT_Vector3 *tan2 = new MT_Vector3[mesh->totvert];
+
+ unsigned int v;
+ for (v = 0; v < mesh->totvert; v++)
+ {
+ tan1[v] = MT_Vector3(0.0, 0.0, 0.0);
+ tan2[v] = MT_Vector3(0.0, 0.0, 0.0);
+ }
+
+ for (unsigned int p = 0; p < mesh->totface; p++, mface++, tface++)
+ {
+ MT_Vector3 v1(mesh->mvert[mface->v1].co),
+ v2(mesh->mvert[mface->v2].co),
+ v3(mesh->mvert[mface->v3].co);
+
+ MT_Vector2 uv1(tface->uv[0]),
+ uv2(tface->uv[1]),
+ uv3(tface->uv[2]);
+
+ BL_ComputeTriTangentSpace(v1, v2, v3, uv1, uv2, uv3, mface, tan1, tan2);
+ if (mface->v4)
+ {
+ MT_Vector3 v4(mesh->mvert[mface->v4].co);
+ MT_Vector2 uv4(tface->uv[3]);
+
+ BL_ComputeTriTangentSpace(v1, v3, v4, uv1, uv3, uv4, mface, tan1, tan2);
+ }
+ }
+
+ MT_Vector4 *tangent = new MT_Vector4[mesh->totvert];
+ for (v = 0; v < mesh->totvert; v++)
+ {
+ const MT_Vector3 no(mesh->mvert[v].no[0]/32767.0,
+ mesh->mvert[v].no[1]/32767.0,
+ mesh->mvert[v].no[2]/32767.0);
+ // Gram-Schmidt orthogonalize
+ MT_Vector3 t(tan1[v] - no.cross(no.cross(tan1[v])));
+ if (!MT_fuzzyZero(t))
+ t /= t.length();
+
+ tangent[v].x() = t.x();
+ tangent[v].y() = t.y();
+ tangent[v].z() = t.z();
+ // Calculate handedness
+ tangent[v].w() = no.dot(tan1[v].cross(tan2[v])) < 0.0 ? -1.0 : 1.0;
+ }
+
+ delete [] tan1;
+ delete [] tan2;
+
+ return tangent;
+}
+
+RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* rendertools, KX_Scene* scene, KX_BlenderSceneConverter *converter)
+{
+ RAS_MeshObject *meshobj;
+ bool skinMesh = false;
+
+ int lightlayer = blenderobj->lay;
+
+ MFace* mface = static_cast<MFace*>(mesh->mface);
+ MTFace* tface = static_cast<MTFace*>(mesh->mtface);
+ MCol* mmcol = mesh->mcol;
+ MT_assert(mface || mesh->totface == 0);
+
+
+ // Determine if we need to make a skinned mesh
+ if (mesh->dvert){
+ meshobj = new BL_SkinMeshObject(lightlayer);
+ skinMesh = true;
+ }
+ else {
+ meshobj = new RAS_MeshObject(lightlayer);
+ }
+ MT_Vector4 *tangent = 0;
+ if (tface)
+ tangent = BL_ComputeMeshTangentSpace(mesh);
+
+
+ // Extract avaiable layers
+ MTF_localLayer *layers = new MTF_localLayer[MAX_MTFACE];
+ for (int lay=0; lay<MAX_MTFACE; lay++)
+ {
+ layers[lay].face = 0;
+ layers[lay].name = "";
+ }
+
+
+ int validLayers = 0;
+ for (int i=0; i<mesh->fdata.totlayer; i++)
+ {
+ if (mesh->fdata.layers[i].type == CD_MTFACE)
+ {
+ assert(validLayers <= 8);
+
+ layers[validLayers].face = (MTFace*)mesh->fdata.layers[i].data;;
+ layers[validLayers].name = mesh->fdata.layers[i].name;
+ validLayers++;
+ }
+ }
+
+
+ meshobj->SetName(mesh->id.name);
+ meshobj->m_xyz_index_to_vertex_index_mapping.resize(mesh->totvert);
+ for (int f=0;f<mesh->totface;f++,mface++)
+ {
+
+ bool collider = true;
+
+ // only add valid polygons
+ if (mface->v3)
+ {
+ MT_Point2 uv0(0.0,0.0),uv1(0.0,0.0),uv2(0.0,0.0),uv3(0.0,0.0);
+ MT_Point2 uv20(0.0,0.0),uv21(0.0,0.0),uv22(0.0,0.0),uv23(0.0,0.0);
+ // rgb3 is set from the adjoint face in a square
+ unsigned int rgb0,rgb1,rgb2,rgb3 = 0;
+ MT_Vector3 no0(mesh->mvert[mface->v1].no[0], mesh->mvert[mface->v1].no[1], mesh->mvert[mface->v1].no[2]),
+ no1(mesh->mvert[mface->v2].no[0], mesh->mvert[mface->v2].no[1], mesh->mvert[mface->v2].no[2]),
+ no2(mesh->mvert[mface->v3].no[0], mesh->mvert[mface->v3].no[1], mesh->mvert[mface->v3].no[2]),
+ no3(0.0, 0.0, 0.0);
+ MT_Point3 pt0(mesh->mvert[mface->v1].co),
+ pt1(mesh->mvert[mface->v2].co),
+ pt2(mesh->mvert[mface->v3].co),
+ pt3(0.0, 0.0, 0.0);
+ MT_Vector4 tan0(0.0, 0.0, 0.0, 0.0),
+ tan1(0.0, 0.0, 0.0, 0.0),
+ tan2(0.0, 0.0, 0.0, 0.0),
+ tan3(0.0, 0.0, 0.0, 0.0);
+
+ no0 /= 32767.0;
+ no1 /= 32767.0;
+ no2 /= 32767.0;
+ if (mface->v4)
+ {
+ pt3 = MT_Point3(mesh->mvert[mface->v4].co);
+ no3 = MT_Vector3(mesh->mvert[mface->v4].no[0], mesh->mvert[mface->v4].no[1], mesh->mvert[mface->v4].no[2]);
+ no3 /= 32767.0;
+ }
+
+ if(!(mface->flag & ME_SMOOTH))
+ {
+ MT_Vector3 norm = ((pt1-pt0).cross(pt2-pt0)).safe_normalized();
+ norm[0] = ((int) (10*norm[0]))/10.0;
+ norm[1] = ((int) (10*norm[1]))/10.0;
+ norm[2] = ((int) (10*norm[2]))/10.0;
+ no0=no1=no2=no3= norm;
+
+ }
+
+ {
+ Material* ma = 0;
+ bool polyvisible = true;
+ RAS_IPolyMaterial* polymat = NULL;
+
+ if(converter->GetMaterials())
+ {
+ if(mesh->totcol > 1)
+ ma = mesh->mat[mface->mat_nr];
+ else
+ ma = give_current_material(blenderobj, 1);
+
+ BL_Material *bl_mat = ConvertMaterial(mesh, ma, tface, mface, mmcol, lightlayer, blenderobj, layers);
+ // set the index were dealing with
+ bl_mat->material_index = (int)mface->mat_nr;
+
+ polyvisible = ((bl_mat->ras_mode & POLY_VIS)!=0);
+ collider = ((bl_mat->ras_mode & COLLIDER)!=0);
+
+ polymat = new KX_BlenderMaterial(scene, bl_mat, skinMesh, lightlayer, blenderobj );
+ converter->RegisterBlenderMaterial(bl_mat);
+
+ unsigned int rgb[4];
+ bl_mat->GetConversionRGB(rgb);
+ rgb0 = rgb[0]; rgb1 = rgb[1];
+ rgb2 = rgb[2]; rgb3 = rgb[3];
+ MT_Point2 uv[4];
+ bl_mat->GetConversionUV(uv);
+ uv0 = uv[0]; uv1 = uv[1];
+ uv2 = uv[2]; uv3 = uv[3];
+
+ bl_mat->GetConversionUV2(uv);
+ uv20 = uv[0]; uv21 = uv[1];
+ uv22 = uv[2]; uv23 = uv[3];
+
+ if(tangent){
+ tan0 = tangent[mface->v1];
+ tan1 = tangent[mface->v2];
+ tan2 = tangent[mface->v3];
+ if (mface->v4)
+ tan3 = tangent[mface->v4];
+ }
+ // this is needed to free up memory afterwards
+ converter->RegisterPolyMaterial(polymat);
+ }
+ else
+ {
+ ma = give_current_material(blenderobj, 1);
+
+ Image* bima = ((mesh->mtface && tface) ? (Image*) tface->tpage : NULL);
+
+ STR_String imastr =
+ ((mesh->mtface && tface) ?
+ (bima? (bima)->id.name : "" ) : "" );
+
+ char transp=0;
+ short mode=0, tile=0;
+ int tilexrep=4,tileyrep = 4;
+
+ if (bima)
+ {
+ tilexrep = bima->xrep;
+ tileyrep = bima->yrep;
+
+ }
+
+ if (mesh->mtface && tface)
+ {
+ // Use texface colors if available
+ //TF_DYNAMIC means the polygon is a collision face
+ collider = ((tface->mode & TF_DYNAMIC) != 0);
+ transp = tface->transp;
+ tile = tface->tile;
+ mode = tface->mode;
+
+ polyvisible = !((mface->flag & ME_HIDE)||(tface->mode & TF_INVISIBLE));
+
+ uv0 = MT_Point2(tface->uv[0]);
+ uv1 = MT_Point2(tface->uv[1]);
+ uv2 = MT_Point2(tface->uv[2]);
+
+ if (mface->v4)
+ uv3 = MT_Point2(tface->uv[3]);
+ }
+ else
+ {
+ // no texfaces, set COLLSION true and everything else FALSE
+
+ mode = default_face_mode;
+ transp = TF_SOLID;
+ tile = 0;
+ }
+
+ if (mmcol)
+ {
+ // Use vertex colors
+ rgb0 = KX_Mcol2uint_new(mmcol[0]);
+ rgb1 = KX_Mcol2uint_new(mmcol[1]);
+ rgb2 = KX_Mcol2uint_new(mmcol[2]);
+
+ if (mface->v4)
+ rgb3 = KX_Mcol2uint_new(mmcol[3]);
+ }
+ else {
+ // no vertex colors: take from material if we have one,
+ // otherwise set to white
+ unsigned int color = 0xFFFFFFFFL;
+
+ if (ma)
+ {
+ union
+ {
+ unsigned char cp[4];
+ unsigned int integer;
+ } col_converter;
+
+ col_converter.cp[3] = (unsigned char) (ma->r*255.0);
+ col_converter.cp[2] = (unsigned char) (ma->g*255.0);
+ col_converter.cp[1] = (unsigned char) (ma->b*255.0);
+ col_converter.cp[0] = (unsigned char) (ma->alpha*255.0);
+
+ color = col_converter.integer;
+ }
+
+ rgb0 = KX_rgbaint2uint_new(color);
+ rgb1 = KX_rgbaint2uint_new(color);
+ rgb2 = KX_rgbaint2uint_new(color);
+
+ if (mface->v4)
+ rgb3 = KX_rgbaint2uint_new(color);
+ }
+
+ bool istriangle = (mface->v4==0);
+ bool zsort = ma?(ma->mode & MA_ZTRA) != 0:false;
+
+ polymat = new KX_PolygonMaterial(imastr, ma,
+ tile, tilexrep, tileyrep,
+ mode, transp, zsort, lightlayer, istriangle, blenderobj, tface, (unsigned int*)mmcol);
+
+ if (ma)
+ {
+ polymat->m_specular = MT_Vector3(ma->specr, ma->specg, ma->specb)*ma->spec;
+ polymat->m_shininess = (float)ma->har/4.0; // 0 < ma->har <= 512
+ polymat->m_diffuse = MT_Vector3(ma->r, ma->g, ma->b)*(ma->emit + ma->ref);
+
+ } else
+ {
+ polymat->m_specular = MT_Vector3(0.0f,0.0f,0.0f);
+ polymat->m_shininess = 35.0;
+ }
+ // this is needed to free up memory afterwards
+ converter->RegisterPolyMaterial(polymat);
+
+ }
+
+ RAS_MaterialBucket* bucket = scene->FindBucket(polymat);
+
+ int nverts = mface->v4?4:3;
+ int vtxarray = meshobj->FindVertexArray(nverts,polymat);
+ RAS_Polygon* poly = new RAS_Polygon(bucket,polyvisible,nverts,vtxarray);
+ if (skinMesh) {
+ int d1, d2, d3, d4=0;
+ bool flat;
+
+ /* If the face is set to solid, all fnors are the same */
+ if (mface->flag & ME_SMOOTH)
+ flat = false;
+ else
+ flat = true;
+
+ d1=((BL_SkinMeshObject*)meshobj)->FindOrAddDeform(vtxarray, mface->v1, &mesh->dvert[mface->v1], polymat);
+ d2=((BL_SkinMeshObject*)meshobj)->FindOrAddDeform(vtxarray, mface->v2, &mesh->dvert[mface->v2], polymat);
+ d3=((BL_SkinMeshObject*)meshobj)->FindOrAddDeform(vtxarray, mface->v3, &mesh->dvert[mface->v3], polymat);
+ if (nverts==4)
+ d4=((BL_SkinMeshObject*)meshobj)->FindOrAddDeform(vtxarray, mface->v4, &mesh->dvert[mface->v4], polymat);
+ poly->SetVertex(0,((BL_SkinMeshObject*)meshobj)->FindOrAddVertex(vtxarray,pt0,uv0,uv20,tan0,rgb0,no0,d1,flat, polymat));
+ poly->SetVertex(1,((BL_SkinMeshObject*)meshobj)->FindOrAddVertex(vtxarray,pt1,uv1,uv21,tan1,rgb1,no1,d2,flat, polymat));
+ poly->SetVertex(2,((BL_SkinMeshObject*)meshobj)->FindOrAddVertex(vtxarray,pt2,uv2,uv22,tan2,rgb2,no2,d3,flat, polymat));
+ if (nverts==4)
+ poly->SetVertex(3,((BL_SkinMeshObject*)meshobj)->FindOrAddVertex(vtxarray,pt3,uv3,uv23,tan3,rgb3,no3,d4, flat,polymat));
+ }
+ else
+ {
+ poly->SetVertex(0,meshobj->FindOrAddVertex(vtxarray,pt0,uv0,uv20,tan0,rgb0,no0,polymat,mface->v1));
+ poly->SetVertex(1,meshobj->FindOrAddVertex(vtxarray,pt1,uv1,uv21,tan1,rgb1,no1,polymat,mface->v2));
+ poly->SetVertex(2,meshobj->FindOrAddVertex(vtxarray,pt2,uv2,uv22,tan2,rgb2,no2,polymat,mface->v3));
+ if (nverts==4)
+ poly->SetVertex(3,meshobj->FindOrAddVertex(vtxarray,pt3,uv3,uv23,tan3,rgb3,no3,polymat,mface->v4));
+ }
+ meshobj->AddPolygon(poly);
+ if (poly->IsCollider())
+ {
+ RAS_TriangleIndex idx;
+ idx.m_index[0] = mface->v1;
+ idx.m_index[1] = mface->v2;
+ idx.m_index[2] = mface->v3;
+ idx.m_collider = collider;
+ meshobj->m_triangle_indices.push_back(idx);
+ if (nverts==4)
+ {
+ idx.m_index[0] = mface->v1;
+ idx.m_index[1] = mface->v3;
+ idx.m_index[2] = mface->v4;
+ idx.m_collider = collider;
+ meshobj->m_triangle_indices.push_back(idx);
+ }
+ }
+
+// poly->SetVisibleWireframeEdges(mface->edcode);
+ poly->SetCollider(collider);
+ }
+ }
+ if (tface)
+ tface++;
+ if (mmcol)
+ mmcol+=4;
+
+ for (int lay=0; lay<MAX_MTFACE; lay++)
+ {
+ MTF_localLayer &layer = layers[lay];
+ if (layer.face == 0) break;
+
+ layer.face++;
+ }
+ }
+ meshobj->UpdateMaterialList();
+
+ // pre calculate texture generation
+ for(RAS_MaterialBucket::Set::iterator mit = meshobj->GetFirstMaterial();
+ mit != meshobj->GetLastMaterial(); ++ mit) {
+ (*mit)->GetPolyMaterial()->OnConstruction();
+ }
+
+ if(tangent)
+ delete [] tangent;
+
+ if (layers)
+ delete []layers;
+
+ return meshobj;
+}
+
+
+
+static PHY_MaterialProps *CreateMaterialFromBlenderObject(struct Object* blenderobject,
+ KX_Scene *kxscene)
+{
+ PHY_MaterialProps *materialProps = new PHY_MaterialProps;
+
+ MT_assert(materialProps && "Create physics material properties failed");
+
+ Material* blendermat = give_current_material(blenderobject, 0);
+
+ if (blendermat)
+ {
+ MT_assert(0.0f <= blendermat->reflect && blendermat->reflect <= 1.0f);
+
+ materialProps->m_restitution = blendermat->reflect;
+ materialProps->m_friction = blendermat->friction;
+ materialProps->m_fh_spring = blendermat->fh;
+ materialProps->m_fh_damping = blendermat->xyfrict;
+ materialProps->m_fh_distance = blendermat->fhdist;
+ materialProps->m_fh_normal = (blendermat->dynamode & MA_FH_NOR) != 0;
+ }
+ else {
+ //give some defaults
+ materialProps->m_restitution = 0.f;
+ materialProps->m_friction = 0.5;
+ materialProps->m_fh_spring = 0.f;
+ materialProps->m_fh_damping = 0.f;
+ materialProps->m_fh_distance = 0.f;
+ materialProps->m_fh_normal = false;
+
+ }
+
+ return materialProps;
+}
+
+static PHY_ShapeProps *CreateShapePropsFromBlenderObject(struct Object* blenderobject,
+ KX_Scene *kxscene)
+{
+ PHY_ShapeProps *shapeProps = new PHY_ShapeProps;
+
+ MT_assert(shapeProps);
+
+ shapeProps->m_mass = blenderobject->mass;
+
+// This needs to be fixed in blender. For now, we use:
+
+// in Blender, inertia stands for the size value which is equivalent to
+// the sphere radius
+ shapeProps->m_inertia = blenderobject->formfactor;
+
+ MT_assert(0.0f <= blenderobject->damping && blenderobject->damping <= 1.0f);
+ MT_assert(0.0f <= blenderobject->rdamping && blenderobject->rdamping <= 1.0f);
+
+ shapeProps->m_lin_drag = 1.0 - blenderobject->damping;
+ shapeProps->m_ang_drag = 1.0 - blenderobject->rdamping;
+
+ shapeProps->m_friction_scaling[0] = blenderobject->anisotropicFriction[0];
+ shapeProps->m_friction_scaling[1] = blenderobject->anisotropicFriction[1];
+ shapeProps->m_friction_scaling[2] = blenderobject->anisotropicFriction[2];
+ shapeProps->m_do_anisotropic = ((blenderobject->gameflag & OB_ANISOTROPIC_FRICTION) != 0);
+
+ shapeProps->m_do_fh = (blenderobject->gameflag & OB_DO_FH) != 0;
+ shapeProps->m_do_rot_fh = (blenderobject->gameflag & OB_ROT_FH) != 0;
+
+ return shapeProps;
+}
+
+
+
+
+
+//////////////////////////////////////////////////////////
+
+
+
+static float my_boundbox_mesh(Mesh *me, float *loc, float *size)
+{
+ MVert *mvert;
+ BoundBox *bb;
+ MT_Point3 min, max;
+ float mloc[3], msize[3];
+ int a;
+
+ if(me->bb==0) me->bb= (struct BoundBox *)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) {
+ loc[0]= (min[0]+max[0])/2.0;
+ loc[1]= (min[1]+max[1])/2.0;
+ loc[2]= (min[2]+max[2])/2.0;
+
+ size[0]= (max[0]-min[0])/2.0;
+ size[1]= (max[1]-min[1])/2.0;
+ size[2]= (max[2]-min[2])/2.0;
+ }
+ else {
+ loc[0]= loc[1]= loc[2]= 0.0;
+ size[0]= size[1]= size[2]= 0.0;
+ }
+
+ bb->vec[0][0]=bb->vec[1][0]=bb->vec[2][0]=bb->vec[3][0]= loc[0]-size[0];
+ bb->vec[4][0]=bb->vec[5][0]=bb->vec[6][0]=bb->vec[7][0]= loc[0]+size[0];
+
+ bb->vec[0][1]=bb->vec[1][1]=bb->vec[4][1]=bb->vec[5][1]= loc[1]-size[1];
+ bb->vec[2][1]=bb->vec[3][1]=bb->vec[6][1]=bb->vec[7][1]= loc[1]+size[1];
+
+ bb->vec[0][2]=bb->vec[3][2]=bb->vec[4][2]=bb->vec[7][2]= loc[2]-size[2];
+ bb->vec[1][2]=bb->vec[2][2]=bb->vec[5][2]=bb->vec[6][2]= loc[2]+size[2];
+
+ float radius = 0;
+ for (a=0, mvert = me->mvert; a < me->totvert; a++, mvert++)
+ {
+ float vert_radius = MT_Vector3(mvert->co).length2();
+ if (vert_radius > radius)
+ radius = vert_radius;
+ }
+ return sqrt(radius);
+}
+
+
+
+
+static void my_tex_space_mesh(Mesh *me)
+ {
+ KeyBlock *kb;
+ float *fp, loc[3], size[3], min[3], max[3];
+ int a;
+
+ my_boundbox_mesh(me, loc, size);
+
+ if(me->texflag & AUTOSPACE) {
+ if(me->key) {
+ kb= me->key->refkey;
+ if (kb) {
+
+ INIT_MINMAX(min, max);
+
+ fp= (float *)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.0; loc[1]= (min[1]+max[1])/2.0; loc[2]= (min[2]+max[2])/2.0;
+ size[0]= (max[0]-min[0])/2.0; size[1]= (max[1]-min[1])/2.0; size[2]= (max[2]-min[2])/2.0;
+ }
+ else {
+ loc[0]= loc[1]= loc[2]= 0.0;
+ size[0]= size[1]= size[2]= 0.0;
+ }
+
+ }
+ }
+
+ VECCOPY(me->loc, loc);
+ VECCOPY(me->size, size);
+ me->rot[0]= me->rot[1]= me->rot[2]= 0.0;
+
+ if(me->size[0]==0.0) me->size[0]= 1.0;
+ else if(me->size[0]>0.0 && me->size[0]<0.00001) me->size[0]= 0.00001;
+ else if(me->size[0]<0.0 && me->size[0]> -0.00001) me->size[0]= -0.00001;
+
+ if(me->size[1]==0.0) me->size[1]= 1.0;
+ else if(me->size[1]>0.0 && me->size[1]<0.00001) me->size[1]= 0.00001;
+ else if(me->size[1]<0.0 && me->size[1]> -0.00001) me->size[1]= -0.00001;
+
+ if(me->size[2]==0.0) me->size[2]= 1.0;
+ else if(me->size[2]>0.0 && me->size[2]<0.00001) me->size[2]= 0.00001;
+ else if(me->size[2]<0.0 && me->size[2]> -0.00001) me->size[2]= -0.00001;
+ }
+
+}
+
+static void my_get_local_bounds(Object *ob, float *center, float *size)
+{
+ BoundBox *bb= NULL;
+ /* uses boundbox, function used by Ketsji */
+ switch (ob->type)
+ {
+ case OB_MESH:
+ bb= ( (Mesh *)ob->data )->bb;
+ if(bb==0)
+ {
+ my_tex_space_mesh((struct Mesh *)ob->data);
+ bb= ( (Mesh *)ob->data )->bb;
+ }
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ center[0]= center[1]= center[2]= 0.0;
+ size[0] = size[1]=size[2]=0.0;
+ break;
+ case OB_MBALL:
+ bb= ob->bb;
+ break;
+ }
+
+ if(bb==NULL)
+ {
+ center[0]= center[1]= center[2]= 0.0;
+ size[0] = size[1]=size[2]=1.0;
+ }
+ 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]= 0.5*(bb->vec[0][0] + bb->vec[4][0]);
+ center[1]= 0.5*(bb->vec[0][1] + bb->vec[2][1]);
+ center[2]= 0.5*(bb->vec[0][2] + bb->vec[1][2]);
+ }
+}
+
+
+
+
+//////////////////////////////////////////////////////
+
+
+
+
+
+void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
+ struct Object* blenderobject,
+ RAS_MeshObject* meshobj,
+ KX_Scene* kxscene,
+ int activeLayerBitInfo,
+ e_PhysicsEngine physics_engine,
+ KX_BlenderSceneConverter *converter,
+ bool processCompoundChildren
+ )
+
+{
+ //SYS_SystemHandle syshandle = SYS_GetSystem(); /*unused*/
+ //int userigidbody = SYS_GetCommandLineInt(syshandle,"norigidbody",0);
+ //bool bRigidBody = (userigidbody == 0);
+
+ // get Root Parent of blenderobject
+ struct Object* parent= blenderobject->parent;
+ while(parent && parent->parent) {
+ parent= parent->parent;
+ }
+
+ bool isCompoundChild = false;
+
+ if (parent && (parent->gameflag & OB_DYNAMIC)) {
+
+ if ((parent->gameflag & OB_CHILD) != 0)
+ {
+ isCompoundChild = true;
+ }
+ }
+ if (processCompoundChildren != isCompoundChild)
+ return;
+
+
+ PHY_ShapeProps* shapeprops =
+ CreateShapePropsFromBlenderObject(blenderobject,
+ kxscene);
+
+
+ PHY_MaterialProps* smmaterial =
+ CreateMaterialFromBlenderObject(blenderobject, kxscene);
+
+ KX_ObjectProperties objprop;
+
+ objprop.m_isCompoundChild = isCompoundChild;
+ objprop.m_hasCompoundChildren = (blenderobject->gameflag & OB_CHILD) != 0;
+
+ if ((objprop.m_isactor = (blenderobject->gameflag & OB_ACTOR)!=0))
+ {
+ objprop.m_dyna = (blenderobject->gameflag & OB_DYNAMIC) != 0;
+ objprop.m_angular_rigidbody = (blenderobject->gameflag & OB_RIGID_BODY) != 0;
+ objprop.m_ghost = (blenderobject->gameflag & OB_GHOST) != 0;
+ objprop.m_disableSleeping = (blenderobject->gameflag & OB_COLLISION_RESPONSE) != 0;//abuse the OB_COLLISION_RESPONSE flag
+ } else {
+ objprop.m_dyna = false;
+ objprop.m_angular_rigidbody = false;
+ objprop.m_ghost = false;
+ objprop.m_disableSleeping = false;
+ }
+ //mmm, for now, taks this for the size of the dynamicobject
+ // Blender uses inertia for radius of dynamic object
+ objprop.m_radius = blenderobject->inertia;
+ objprop.m_in_active_layer = (blenderobject->lay & activeLayerBitInfo) != 0;
+ objprop.m_dynamic_parent=NULL;
+ objprop.m_isdeformable = ((blenderobject->gameflag2 & 2)) != 0;
+ objprop.m_boundclass = objprop.m_dyna?KX_BOUNDSPHERE:KX_BOUNDMESH;
+ KX_BoxBounds bb;
+ my_get_local_bounds(blenderobject,objprop.m_boundobject.box.m_center,bb.m_extends);
+ if (blenderobject->gameflag & OB_BOUNDS)
+ {
+ switch (blenderobject->boundtype)
+ {
+ case OB_BOUND_BOX:
+ objprop.m_boundclass = KX_BOUNDBOX;
+ //mmm, has to be divided by 2 to be proper extends
+ objprop.m_boundobject.box.m_extends[0]=2.f*bb.m_extends[0];
+ objprop.m_boundobject.box.m_extends[1]=2.f*bb.m_extends[1];
+ objprop.m_boundobject.box.m_extends[2]=2.f*bb.m_extends[2];
+ break;
+ case OB_BOUND_POLYT:
+ if (blenderobject->type == OB_MESH)
+ {
+ objprop.m_boundclass = KX_BOUNDPOLYTOPE;
+ break;
+ }
+ // Object is not a mesh... fall through OB_BOUND_POLYH to
+ // OB_BOUND_SPHERE
+ case OB_BOUND_POLYH:
+ if (blenderobject->type == OB_MESH)
+ {
+ objprop.m_boundclass = KX_BOUNDMESH;
+ break;
+ }
+ // Object is not a mesh... can't use polyheder.
+ // Fall through and become a sphere.
+ case OB_BOUND_SPHERE:
+ {
+ objprop.m_boundclass = KX_BOUNDSPHERE;
+ objprop.m_boundobject.c.m_radius = MT_max(bb.m_extends[0], MT_max(bb.m_extends[1], bb.m_extends[2]));
+ break;
+ }
+ case OB_BOUND_CYLINDER:
+ {
+ objprop.m_boundclass = KX_BOUNDCYLINDER;
+ objprop.m_boundobject.c.m_radius = MT_max(bb.m_extends[0], bb.m_extends[1]);
+ objprop.m_boundobject.c.m_height = 2.f*bb.m_extends[2];
+ break;
+ }
+ case OB_BOUND_CONE:
+ {
+ objprop.m_boundclass = KX_BOUNDCONE;
+ objprop.m_boundobject.c.m_radius = MT_max(bb.m_extends[0], bb.m_extends[1]);
+ objprop.m_boundobject.c.m_height = 2.f*bb.m_extends[2];
+ break;
+ }
+ }
+ }
+
+
+ if (parent && (parent->gameflag & OB_DYNAMIC)) {
+
+ KX_GameObject *parentgameobject = converter->FindGameObject(parent);
+ objprop.m_dynamic_parent = parentgameobject;
+ //cannot be dynamic:
+ objprop.m_dyna = false;
+ shapeprops->m_mass = 0.f;
+ }
+
+
+ objprop.m_concave = (blenderobject->boundtype & 4) != 0;
+
+ switch (physics_engine)
+ {
+#ifdef USE_BULLET
+ case UseBullet:
+ KX_ConvertBulletObject(gameobj, meshobj, kxscene, shapeprops, smmaterial, &objprop);
+ break;
+
+#endif
+#ifdef USE_SUMO_SOLID
+ case UseSumo:
+ KX_ConvertSumoObject(gameobj, meshobj, kxscene, shapeprops, smmaterial, &objprop);
+ break;
+#endif
+
+#ifdef USE_ODE
+ case UseODE:
+ KX_ConvertODEEngineObject(gameobj, meshobj, kxscene, shapeprops, smmaterial, &objprop);
+ break;
+#endif //USE_ODE
+
+ case UseDynamo:
+ //KX_ConvertDynamoObject(gameobj,meshobj,kxscene,shapeprops, smmaterial, &objprop);
+ break;
+
+ case UseNone:
+ default:
+ break;
+ }
+
+}
+
+
+
+
+
+static KX_LightObject *gamelight_from_blamp(Lamp *la, unsigned int layerflag, KX_Scene *kxscene, RAS_IRenderTools *rendertools, KX_BlenderSceneConverter *converter) {
+ RAS_LightObject lightobj;
+ KX_LightObject *gamelight;
+
+ lightobj.m_att1 = la->att1;
+ lightobj.m_att2 = (la->mode & LA_QUAD)?la->att2:0.0;
+ lightobj.m_red = la->r;
+ lightobj.m_green = la->g;
+ lightobj.m_blue = la->b;
+ lightobj.m_distance = la->dist;
+ lightobj.m_energy = la->energy;
+ lightobj.m_layer = layerflag;
+ lightobj.m_spotblend = la->spotblend;
+ lightobj.m_spotsize = la->spotsize;
+
+ lightobj.m_nodiffuse = (la->mode & LA_NO_DIFF) != 0;
+ lightobj.m_nospecular = (la->mode & LA_NO_SPEC) != 0;
+
+ if (la->mode & LA_NEG)
+ {
+ lightobj.m_red = -lightobj.m_red;
+ lightobj.m_green = -lightobj.m_green;
+ lightobj.m_blue = -lightobj.m_blue;
+ }
+
+ if (la->type==LA_SUN) {
+ lightobj.m_type = RAS_LightObject::LIGHT_SUN;
+ } else if (la->type==LA_SPOT) {
+ lightobj.m_type = RAS_LightObject::LIGHT_SPOT;
+ } else {
+ lightobj.m_type = RAS_LightObject::LIGHT_NORMAL;
+ }
+
+ gamelight = new KX_LightObject(kxscene, KX_Scene::m_callbacks, rendertools, lightobj);
+ BL_ConvertLampIpos(la, gamelight, converter);
+
+ return gamelight;
+}
+
+static KX_Camera *gamecamera_from_bcamera(Camera *ca, KX_Scene *kxscene, KX_BlenderSceneConverter *converter) {
+ RAS_CameraData camdata(ca->lens, ca->clipsta, ca->clipend, ca->type == CAM_PERSP);
+ KX_Camera *gamecamera;
+
+ gamecamera= new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata);
+ gamecamera->SetName(ca->id.name + 2);
+
+ BL_ConvertCameraIpos(ca, gamecamera, converter);
+
+ return gamecamera;
+}
+
+static KX_GameObject *gameobject_from_blenderobject(
+ Object *ob,
+ KX_Scene *kxscene,
+ RAS_IRenderTools *rendertools,
+ KX_BlenderSceneConverter *converter,
+ Scene *blenderscene)
+{
+ KX_GameObject *gameobj = NULL;
+
+ switch(ob->type)
+ {
+ case OB_LAMP:
+ {
+ KX_LightObject* gamelight= gamelight_from_blamp(static_cast<Lamp*>(ob->data), ob->lay, kxscene, rendertools, converter);
+ gameobj = gamelight;
+
+ gamelight->AddRef();
+ kxscene->GetLightList()->Add(gamelight);
+
+ break;
+ }
+
+ case OB_CAMERA:
+ {
+ KX_Camera* gamecamera = gamecamera_from_bcamera(static_cast<Camera*>(ob->data), kxscene, converter);
+ gameobj = gamecamera;
+
+ gamecamera->AddRef();
+ kxscene->AddCamera(gamecamera);
+
+ break;
+ }
+
+ case OB_MESH:
+ {
+ Mesh* mesh = static_cast<Mesh*>(ob->data);
+ RAS_MeshObject* meshobj = converter->FindGameMesh(mesh, ob->lay);
+ float center[3], extents[3];
+ float radius = my_boundbox_mesh((Mesh*) ob->data, center, extents);
+
+ if (!meshobj) {
+ meshobj = BL_ConvertMesh(mesh,ob,rendertools,kxscene,converter);
+ converter->RegisterGameMesh(meshobj, mesh);
+ }
+
+ // needed for python scripting
+ kxscene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj);
+
+ gameobj = new BL_DeformableGameObject(kxscene,KX_Scene::m_callbacks);
+
+ // set transformation
+ gameobj->AddMesh(meshobj);
+
+ // for all objects: check whether they want to
+ // respond to updates
+ bool ignoreActivityCulling =
+ ((ob->gameflag2 & OB_NEVER_DO_ACTIVITY_CULLING)!=0);
+ gameobj->SetIgnoreActivityCulling(ignoreActivityCulling);
+
+ // If this is a skin object, make Skin Controller
+ if (ob->parent && ob->parent->type == OB_ARMATURE && ob->partype==PARSKEL && ((Mesh*)ob->data)->dvert){
+ BL_SkinDeformer *dcont = new BL_SkinDeformer(ob, (BL_SkinMeshObject*)meshobj );
+ ((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont;
+ }
+ else if (((Mesh*)ob->data)->dvert){
+ BL_MeshDeformer *dcont = new BL_MeshDeformer(ob, (BL_SkinMeshObject*)meshobj );
+ ((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont;
+ }
+
+ MT_Point3 min = MT_Point3(center) - MT_Vector3(extents);
+ MT_Point3 max = MT_Point3(center) + MT_Vector3(extents);
+ SG_BBox bbox = SG_BBox(min, max);
+ gameobj->GetSGNode()->SetBBox(bbox);
+ gameobj->GetSGNode()->SetRadius(radius);
+
+ break;
+ }
+
+ case OB_ARMATURE:
+ {
+ gameobj = new BL_ArmatureObject(
+ kxscene,
+ KX_Scene::m_callbacks,
+ ob // handle
+ );
+ /* Get the current pose from the armature object and apply it as the rest pose */
+ break;
+ }
+
+ case OB_EMPTY:
+ {
+ gameobj = new KX_EmptyObject(kxscene,KX_Scene::m_callbacks);
+ // set transformation
+ break;
+ }
+ }
+
+ return gameobj;
+}
+
+struct parentChildLink {
+ struct Object* m_blenderchild;
+ SG_Node* m_gamechildnode;
+};
+
+ /**
+ * Find the specified scene by name, or the first
+ * scene if nothing matches (shouldn't happen).
+ */
+static struct Scene *GetSceneForName(struct Main *maggie, const STR_String& scenename) {
+ Scene *sce;
+
+ for (sce= (Scene*) maggie->scene.first; sce; sce= (Scene*) sce->id.next)
+ if (scenename == (sce->id.name+2))
+ return sce;
+
+ return (Scene*) maggie->scene.first;
+}
+
+#include "DNA_constraint_types.h"
+#include "BIF_editconstraint.h"
+
+bPoseChannel *get_active_posechannel2 (Object *ob)
+{
+ bArmature *arm= (bArmature*)ob->data;
+ bPoseChannel *pchan;
+
+ /* find active */
+ for(pchan= (bPoseChannel *)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;
+}
+
+ListBase *get_active_constraints2(Object *ob)
+{
+ if (!ob)
+ return NULL;
+
+ if (ob->flag & OB_POSEMODE) {
+ bPoseChannel *pchan;
+
+ pchan = get_active_posechannel2(ob);
+ if (pchan)
+ return &pchan->constraints;
+ }
+ else
+ return &ob->constraints;
+
+ return NULL;
+}
+
+
+void RBJconstraints(Object *ob)//not used
+{
+ ListBase *conlist;
+ bConstraint *curcon;
+
+ conlist = get_active_constraints2(ob);
+
+ if (conlist) {
+ for (curcon = (bConstraint *)conlist->first; curcon; curcon=(bConstraint *)curcon->next) {
+
+ printf("%i\n",curcon->type);
+ }
+
+
+ }
+}
+
+#include "PHY_IPhysicsEnvironment.h"
+#include "KX_IPhysicsController.h"
+#include "PHY_DynamicTypes.h"
+
+KX_IPhysicsController* getPhId(CListValue* sumolist,STR_String busc){//not used
+
+ for (int j=0;j<sumolist->GetCount();j++)
+ {
+ KX_GameObject* gameobje = (KX_GameObject*) sumolist->GetValue(j);
+ if (gameobje->GetName()==busc)
+ return gameobje->GetPhysicsController();
+ }
+
+ return 0;
+
+}
+
+KX_GameObject* getGameOb(STR_String busc,CListValue* sumolist){
+
+ for (int j=0;j<sumolist->GetCount();j++)
+ {
+ KX_GameObject* gameobje = (KX_GameObject*) sumolist->GetValue(j);
+ if (gameobje->GetName()==busc)
+ return gameobje;
+ }
+
+ return 0;
+
+}
+#include "BLI_arithb.h"
+// convert blender objects into ketsji gameobjects
+void BL_ConvertBlenderObjects(struct Main* maggie,
+ const STR_String& scenename,
+ KX_Scene* kxscene,
+ KX_KetsjiEngine* ketsjiEngine,
+ e_PhysicsEngine physics_engine,
+ PyObject* pythondictionary,
+ SCA_IInputDevice* keydev,
+ RAS_IRenderTools* rendertools,
+ RAS_ICanvas* canvas,
+ KX_BlenderSceneConverter* converter,
+ bool alwaysUseExpandFraming
+ )
+{
+
+ Scene *blenderscene = GetSceneForName(maggie, scenename);
+
+ // Get the frame settings of the canvas.
+ // Get the aspect ratio of the canvas as designed by the user.
+
+ RAS_FrameSettings::RAS_FrameType frame_type;
+ int aspect_width;
+ int aspect_height;
+ vector<MT_Vector3> inivel,iniang;
+
+ if (alwaysUseExpandFraming) {
+ frame_type = RAS_FrameSettings::e_frame_extend;
+ aspect_width = canvas->GetWidth();
+ aspect_height = canvas->GetHeight();
+ } else {
+ if (blenderscene->framing.type == SCE_GAMEFRAMING_BARS) {
+ frame_type = RAS_FrameSettings::e_frame_bars;
+ } else if (blenderscene->framing.type == SCE_GAMEFRAMING_EXTEND) {
+ frame_type = RAS_FrameSettings::e_frame_extend;
+ } else {
+ frame_type = RAS_FrameSettings::e_frame_scale;
+ }
+
+ aspect_width = blenderscene->r.xsch;
+ aspect_height = blenderscene->r.ysch;
+ }
+
+ RAS_FrameSettings frame_settings(
+ frame_type,
+ blenderscene->framing.col[0],
+ blenderscene->framing.col[1],
+ blenderscene->framing.col[2],
+ aspect_width,
+ aspect_height
+ );
+ kxscene->SetFramingType(frame_settings);
+
+ kxscene->SetGravity(MT_Vector3(0,0,(blenderscene->world != NULL) ? -blenderscene->world->gravity : -9.8));
+
+ /* set activity culling parameters */
+ if (blenderscene->world) {
+ kxscene->SetActivityCulling( (blenderscene->world->mode & WO_ACTIVITY_CULLING) != 0);
+ kxscene->SetActivityCullingRadius(blenderscene->world->activityBoxRadius);
+ } else {
+ kxscene->SetActivityCulling(false);
+ }
+
+ int activeLayerBitInfo = blenderscene->lay;
+
+ // templist to find Root Parents (object with no parents)
+ CListValue* templist = new CListValue();
+ CListValue* sumolist = new CListValue();
+
+ vector<parentChildLink> vec_parent_child;
+
+ CListValue* objectlist = kxscene->GetObjectList();
+ CListValue* parentlist = kxscene->GetRootParentList();
+
+ SCA_LogicManager* logicmgr = kxscene->GetLogicManager();
+ SCA_TimeEventManager* timemgr = kxscene->GetTimeEventManager();
+
+ CListValue* logicbrick_conversionlist = new CListValue();
+
+ SG_TreeFactory tf;
+
+ // Convert actions to actionmap
+ bAction *curAct;
+ for (curAct = (bAction*)maggie->action.first; curAct; curAct=(bAction*)curAct->id.next)
+ {
+ logicmgr->RegisterActionName(curAct->id.name, curAct);
+ }
+
+ SetDefaultFaceType(blenderscene);
+
+ Base *base = static_cast<Base*>(blenderscene->base.first);
+ while(base)
+ {
+ Object* blenderobject = base->object;
+ KX_GameObject* gameobj = gameobject_from_blenderobject(
+ base->object,
+ kxscene,
+ rendertools,
+ converter,
+ blenderscene);
+
+ bool isInActiveLayer = (blenderobject->lay & activeLayerBitInfo) !=0;
+ bool addobj=true;
+
+ if (converter->addInitFromFrame)
+ if (!isInActiveLayer)
+ addobj=false;
+
+ if (gameobj&&addobj)
+ {
+ MT_Point3 posPrev;
+ MT_Matrix3x3 angor;
+ if (converter->addInitFromFrame) blenderscene->r.cfra=blenderscene->r.sfra;
+
+ MT_Point3 pos = MT_Point3(
+ blenderobject->loc[0]+blenderobject->dloc[0],
+ blenderobject->loc[1]+blenderobject->dloc[1],
+ blenderobject->loc[2]+blenderobject->dloc[2]
+ );
+ MT_Vector3 eulxyz = MT_Vector3(
+ blenderobject->rot[0],
+ blenderobject->rot[1],
+ blenderobject->rot[2]
+ );
+ MT_Vector3 scale = MT_Vector3(
+ blenderobject->size[0],
+ blenderobject->size[1],
+ blenderobject->size[2]
+ );
+ if (converter->addInitFromFrame){//rcruiz
+ float eulxyzPrev[3];
+ blenderscene->r.cfra=blenderscene->r.sfra-1;
+ update_for_newframe();
+ MT_Vector3 tmp=pos-MT_Point3(blenderobject->loc[0]+blenderobject->dloc[0],
+ blenderobject->loc[1]+blenderobject->dloc[1],
+ blenderobject->loc[2]+blenderobject->dloc[2]
+ );
+ eulxyzPrev[0]=blenderobject->rot[0];
+ eulxyzPrev[1]=blenderobject->rot[1];
+ eulxyzPrev[2]=blenderobject->rot[2];
+
+ double fps = (double) blenderscene->r.frs_sec/
+ (double) blenderscene->r.frs_sec_base;
+
+ tmp.scale(fps, fps, fps);
+ inivel.push_back(tmp);
+ tmp=eulxyz-eulxyzPrev;
+ tmp.scale(fps, fps, fps);
+ iniang.push_back(tmp);
+ blenderscene->r.cfra=blenderscene->r.sfra;
+ update_for_newframe();
+ }
+
+ gameobj->NodeSetLocalPosition(pos);
+ gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz));
+ gameobj->NodeSetLocalScale(scale);
+ gameobj->NodeUpdateGS(0,true);
+
+ BL_ConvertIpos(blenderobject,gameobj,converter);
+ // TODO: expand to multiple ipos per mesh
+ Material *mat = give_current_material(blenderobject, 1);
+ if(mat) BL_ConvertMaterialIpos(mat, gameobj, converter);
+
+ sumolist->Add(gameobj->AddRef());
+
+ BL_ConvertProperties(blenderobject,gameobj,timemgr,kxscene,isInActiveLayer);
+
+
+ gameobj->SetName(blenderobject->id.name);
+
+ // templist to find Root Parents (object with no parents)
+ templist->Add(gameobj->AddRef());
+
+ // update children/parent hierarchy
+ if ((blenderobject->parent != 0)&&(!converter->addInitFromFrame))
+ {
+ // blender has an additional 'parentinverse' offset in each object
+ SG_Node* parentinversenode = new SG_Node(NULL,NULL,SG_Callbacks());
+
+ // define a normal parent relationship for this node.
+ KX_NormalParentRelation * parent_relation = KX_NormalParentRelation::New();
+ parentinversenode->SetParentRelation(parent_relation);
+
+ parentChildLink pclink;
+ pclink.m_blenderchild = blenderobject;
+ pclink.m_gamechildnode = parentinversenode;
+ vec_parent_child.push_back(pclink);
+
+ float* fl = (float*) blenderobject->parentinv;
+ MT_Transform parinvtrans(fl);
+ parentinversenode->SetLocalPosition(parinvtrans.getOrigin());
+ parentinversenode->SetLocalOrientation(parinvtrans.getBasis());
+
+ parentinversenode->AddChild(gameobj->GetSGNode());
+ }
+
+ // needed for python scripting
+ logicmgr->RegisterGameObjectName(gameobj->GetName(),gameobj);
+
+ // needed for dynamic object morphing
+ logicmgr->RegisterGameObj(gameobj, blenderobject);
+ for (int i = 0; i < gameobj->GetMeshCount(); i++)
+ logicmgr->RegisterGameMeshName(gameobj->GetMesh(i)->GetName(), blenderobject);
+
+ converter->RegisterGameObject(gameobj, blenderobject);
+ // this was put in rapidly, needs to be looked at more closely
+ // only draw/use objects in active 'blender' layers
+
+ logicbrick_conversionlist->Add(gameobj->AddRef());
+
+ if (converter->addInitFromFrame){
+ posPrev=gameobj->NodeGetWorldPosition();
+ angor=gameobj->NodeGetWorldOrientation();
+ }
+ if (isInActiveLayer)
+ {
+ objectlist->Add(gameobj->AddRef());
+ tf.Add(gameobj->GetSGNode());
+
+ gameobj->NodeUpdateGS(0,true);
+ gameobj->Bucketize();
+
+ }
+ if (converter->addInitFromFrame){
+ gameobj->NodeSetLocalPosition(posPrev);
+ gameobj->NodeSetLocalOrientation(angor);
+ }
+
+ }
+
+ base = base->next;
+ }
+
+ if (blenderscene->camera) {
+ KX_Camera *gamecamera= (KX_Camera*) converter->FindGameObject(blenderscene->camera);
+
+ kxscene->SetActiveCamera(gamecamera);
+ }
+
+ // Set up armatures
+ for (base = static_cast<Base*>(blenderscene->base.first); base; base=base->next){
+ if (base->object->type==OB_MESH){
+ Mesh *me = (Mesh*)base->object->data;
+
+ if (me->dvert){
+ KX_GameObject *obj = converter->FindGameObject(base->object);
+
+ if (base->object->parent && base->object->parent->type==OB_ARMATURE && base->object->partype==PARSKEL){
+ KX_GameObject *par = converter->FindGameObject(base->object->parent);
+ if (par)
+ ((BL_SkinDeformer*)(((BL_DeformableGameObject*)obj)->m_pDeformer))->SetArmature((BL_ArmatureObject*) par);
+ }
+ }
+ }
+ }
+
+ // create hierarchy information
+ int i;
+ vector<parentChildLink>::iterator pcit;
+
+ for (pcit = vec_parent_child.begin();!(pcit==vec_parent_child.end());++pcit)
+ {
+
+ struct Object* blenderchild = pcit->m_blenderchild;
+ switch (blenderchild->partype)
+ {
+ case PARVERT1:
+ {
+ // creat a new vertex parent relationship for this node.
+ KX_VertexParentRelation * vertex_parent_relation = KX_VertexParentRelation::New();
+ pcit->m_gamechildnode->SetParentRelation(vertex_parent_relation);
+ break;
+ }
+ case PARSLOW:
+ {
+ // creat a new slow parent relationship for this node.
+ KX_SlowParentRelation * slow_parent_relation = KX_SlowParentRelation::New(blenderchild->sf);
+ pcit->m_gamechildnode->SetParentRelation(slow_parent_relation);
+ break;
+ }
+ case PARBONE:
+ {
+ // parent this to a bone
+ Bone *parent_bone = get_named_bone(get_armature(blenderchild->parent), blenderchild->parsubstr);
+ KX_BoneParentRelation *bone_parent_relation = KX_BoneParentRelation::New(parent_bone);
+ pcit->m_gamechildnode->SetParentRelation(bone_parent_relation);
+
+ break;
+ }
+ case PARSKEL: // skinned - ignore
+ break;
+ case PAROBJECT:
+ case PARCURVE:
+ case PARKEY:
+ case PARVERT3:
+ default:
+ // unhandled
+ break;
+ }
+
+ struct Object* blenderparent = blenderchild->parent;
+ KX_GameObject* parentobj = converter->FindGameObject(blenderparent);
+ if (parentobj)
+ {
+ parentobj-> GetSGNode()->AddChild(pcit->m_gamechildnode);
+ }
+ }
+ vec_parent_child.clear();
+
+ // find 'root' parents (object that has not parents in SceneGraph)
+ for (i=0;i<templist->GetCount();++i)
+ {
+ KX_GameObject* gameobj = (KX_GameObject*) templist->GetValue(i);
+ if (gameobj->GetSGNode()->GetSGParent() == 0)
+ {
+ parentlist->Add(gameobj->AddRef());
+ gameobj->NodeUpdateGS(0,true);
+ }
+ }
+
+ bool processCompoundChildren = false;
+
+ // create physics information
+ for (i=0;i<sumolist->GetCount();i++)
+ {
+ KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
+ struct Object* blenderobject = converter->FindBlenderObject(gameobj);
+ int nummeshes = gameobj->GetMeshCount();
+ RAS_MeshObject* meshobj = 0;
+ if (nummeshes > 0)
+ {
+ meshobj = gameobj->GetMesh(0);
+ }
+ BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,activeLayerBitInfo,physics_engine,converter,processCompoundChildren);
+ }
+
+ processCompoundChildren = true;
+ // create physics information
+ for (i=0;i<sumolist->GetCount();i++)
+ {
+ KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
+ struct Object* blenderobject = converter->FindBlenderObject(gameobj);
+ int nummeshes = gameobj->GetMeshCount();
+ RAS_MeshObject* meshobj = 0;
+ if (nummeshes > 0)
+ {
+ meshobj = gameobj->GetMesh(0);
+ }
+ BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,activeLayerBitInfo,physics_engine,converter,processCompoundChildren);
+ }
+
+
+ //set ini linearVel and int angularVel //rcruiz
+ if (converter->addInitFromFrame)
+ for (i=0;i<sumolist->GetCount();i++)
+ {
+ KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
+ if (gameobj->IsDynamic()){
+ gameobj->setLinearVelocity(inivel[i],false);
+ gameobj->setAngularVelocity(iniang[i],false);
+ }
+
+
+ }
+
+ // create physics joints
+ for (i=0;i<sumolist->GetCount();i++)
+ {
+ KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
+ struct Object* blenderobject = converter->FindBlenderObject(gameobj);
+ int nummeshes = gameobj->GetMeshCount();
+ RAS_MeshObject* meshobj = 0;
+ ListBase *conlist;
+ bConstraint *curcon;
+ conlist = get_active_constraints2(blenderobject);
+ if (conlist) {
+ for (curcon = (bConstraint *)conlist->first; curcon; curcon=(bConstraint *)curcon->next) {
+ if (curcon->type==CONSTRAINT_TYPE_RIGIDBODYJOINT){
+ bRigidBodyJointConstraint *dat=(bRigidBodyJointConstraint *)curcon->data;
+ //if (dat->tar)
+ if (!dat->child){
+ PHY_IPhysicsController* physctr2 = 0;
+ if (dat->tar)
+ {
+ KX_GameObject *gotar=getGameOb(dat->tar->id.name,sumolist);
+ if (gotar && gotar->GetPhysicsController())
+ physctr2 = (PHY_IPhysicsController*) gotar->GetPhysicsController()->GetUserData();
+ }
+
+ if (gameobj->GetPhysicsController())
+ {
+ float radsPerDeg = 6.283185307179586232f / 360.f;
+
+ PHY_IPhysicsController* physctrl = (PHY_IPhysicsController*) gameobj->GetPhysicsController()->GetUserData();
+ //we need to pass a full constraint frame, not just axis
+
+ //localConstraintFrameBasis
+ MT_Matrix3x3 localCFrame(MT_Vector3(radsPerDeg*dat->axX,radsPerDeg*dat->axY,radsPerDeg*dat->axZ));
+ MT_Vector3 axis0 = localCFrame.getColumn(0);
+ MT_Vector3 axis1 = localCFrame.getColumn(1);
+ MT_Vector3 axis2 = localCFrame.getColumn(2);
+
+ int constraintId = kxscene->GetPhysicsEnvironment()->createConstraint(physctrl,physctr2,(PHY_ConstraintType)dat->type,(float)dat->pivX,(float)dat->pivY,(float)dat->pivZ,
+ (float)axis0.x(),(float)axis0.y(),(float)axis0.z(),
+ (float)axis1.x(),(float)axis1.y(),(float)axis1.z(),
+ (float)axis2.x(),(float)axis2.y(),(float)axis2.z()
+ );
+ if (constraintId)
+ {
+ //if it is a generic 6DOF constraint, set all the limits accordingly
+ if (dat->type == PHY_GENERIC_6DOF_CONSTRAINT)
+ {
+ int dof;
+ int dofbit=1;
+ for (dof=0;dof<6;dof++)
+ {
+ if (dat->flag & dofbit)
+ {
+ kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,dat->minLimit[dof],dat->maxLimit[dof]);
+ } else
+ {
+ //minLimit > maxLimit means free(disabled limit) for this degree of freedom
+ kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,1,-1);
+ }
+ dofbit<<=1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ templist->Release();
+ sumolist->Release();
+
+ int executePriority=0; /* incremented by converter routines */
+
+ // convert global sound stuff
+
+ /* XXX, glob is the very very wrong place for this
+ * to be, re-enable once the listener has been moved into
+ * the scene. */
+#if 1
+ SND_Scene* soundscene = kxscene->GetSoundScene();
+ SND_SoundListener* listener = soundscene->GetListener();
+ if (listener && G.listener)
+ {
+ listener->SetDopplerFactor(G.listener->dopplerfactor);
+ listener->SetDopplerVelocity(G.listener->dopplervelocity);
+ listener->SetGain(G.listener->gain);
+ }
+#endif
+
+ // convert world
+ KX_WorldInfo* worldinfo = new BlenderWorldInfo(blenderscene->world);
+ converter->RegisterWorldInfo(worldinfo);
+ kxscene->SetWorldInfo(worldinfo);
+
+#define CONVERT_LOGIC
+#ifdef CONVERT_LOGIC
+ // convert logic bricks, sensors, controllers and actuators
+ for (i=0;i<logicbrick_conversionlist->GetCount();i++)
+ {
+ KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i));
+ struct Object* blenderobj = converter->FindBlenderObject(gameobj);
+ bool isInActiveLayer = (blenderobj->lay & activeLayerBitInfo)!=0;
+ BL_ConvertActuators(maggie->name, blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,executePriority, activeLayerBitInfo,isInActiveLayer,rendertools,converter);
+ }
+ for ( i=0;i<logicbrick_conversionlist->GetCount();i++)
+ {
+ KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i));
+ struct Object* blenderobj = converter->FindBlenderObject(gameobj);
+ bool isInActiveLayer = (blenderobj->lay & activeLayerBitInfo)!=0;
+ BL_ConvertControllers(blenderobj,gameobj,logicmgr,pythondictionary,executePriority,activeLayerBitInfo,isInActiveLayer,converter);
+ }
+ for ( i=0;i<logicbrick_conversionlist->GetCount();i++)
+ {
+ KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i));
+ struct Object* blenderobj = converter->FindBlenderObject(gameobj);
+ bool isInActiveLayer = (blenderobj->lay & activeLayerBitInfo)!=0;
+ BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,keydev,executePriority,activeLayerBitInfo,isInActiveLayer,canvas,converter);
+ }
+#endif //CONVERT_LOGIC
+
+ logicbrick_conversionlist->Release();
+
+ // Calculate the scene btree -
+ // too slow - commented out.
+ //kxscene->SetNodeTree(tf.MakeTree());
+}
+
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.h b/source/gameengine/Converter/BL_BlenderDataConversion.h
new file mode 100644
index 00000000000..56dc5bfa8b2
--- /dev/null
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.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 __BLENDER_CONVERT
+#define __BLENDER_CONVERT
+
+#include "GEN_HashedPtr.h"
+#include "STR_String.h"
+#include "KX_Python.h"
+#include "KX_PhysicsEngineEnums.h"
+
+class RAS_MeshObject* BL_ConvertMesh(struct Mesh* mesh,struct Object* lightobj,class RAS_IRenderTools* rendertools,class KX_Scene* scene, class KX_BlenderSceneConverter *converter);
+
+void BL_ConvertBlenderObjects(struct Main* maggie,
+ const STR_String& scenename,
+ class KX_Scene* kxscene,
+ class KX_KetsjiEngine* ketsjiEngine,
+ e_PhysicsEngine physics_engine,
+ PyObject* pythondictionary,
+ class SCA_IInputDevice* keydev,
+ class RAS_IRenderTools* rendertools,
+ class RAS_ICanvas* canvas,
+ class KX_BlenderSceneConverter* sceneconverter,
+ bool alwaysUseExpandFraming
+ );
+
+#endif // __BLENDER_CONVERT
+
diff --git a/source/gameengine/Converter/BL_DeformableGameObject.cpp b/source/gameengine/Converter/BL_DeformableGameObject.cpp
new file mode 100644
index 00000000000..a17ca6a7c19
--- /dev/null
+++ b/source/gameengine/Converter/BL_DeformableGameObject.cpp
@@ -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 *****
+ */
+
+#include "BL_DeformableGameObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+BL_DeformableGameObject::~BL_DeformableGameObject()
+{
+ if (m_pDeformer)
+ delete m_pDeformer; // __NLA : Temporary until we decide where to put this
+}
+
+void BL_DeformableGameObject::ProcessReplica(KX_GameObject* replica)
+{
+ KX_GameObject::ProcessReplica(replica);
+
+ if (m_pDeformer){
+ ((BL_DeformableGameObject*)replica)->m_pDeformer = m_pDeformer->GetReplica();
+ }
+
+}
+
+CValue* BL_DeformableGameObject::GetReplica()
+{
+
+ BL_DeformableGameObject* replica = new BL_DeformableGameObject(*this);//m_float,GetName());
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ ProcessReplica(replica);
+ return replica;
+}
diff --git a/source/gameengine/Converter/BL_DeformableGameObject.h b/source/gameengine/Converter/BL_DeformableGameObject.h
new file mode 100644
index 00000000000..720a152575a
--- /dev/null
+++ b/source/gameengine/Converter/BL_DeformableGameObject.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 BL_DEFORMABLEGAMEOBJECT
+#define BL_DEFORMABLEGAMEOBJECT
+
+#ifdef WIN32
+#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
+#endif //WIN32
+
+#include "KX_GameObject.h"
+#include "RAS_Deformer.h"
+
+class BL_DeformableGameObject : public KX_GameObject
+{
+public:
+
+ RAS_Deformer *m_pDeformer;
+ CValue* GetReplica();
+ virtual void Relink(GEN_Map<GEN_HashedPtr, void*>*map)
+ {
+ if (m_pDeformer)
+ m_pDeformer->Relink (map);
+ };
+ void ProcessReplica(KX_GameObject* replica);
+
+ BL_DeformableGameObject(void* sgReplicationInfo, SG_Callbacks callbacks) :
+ KX_GameObject(sgReplicationInfo,callbacks),
+ m_pDeformer(NULL)
+ {
+ m_isDeformable = true;
+ };
+ virtual ~BL_DeformableGameObject();
+
+};
+
+#endif
+
diff --git a/source/gameengine/Converter/BL_MeshDeformer.cpp b/source/gameengine/Converter/BL_MeshDeformer.cpp
new file mode 100644
index 00000000000..4555e81254a
--- /dev/null
+++ b/source/gameengine/Converter/BL_MeshDeformer.cpp
@@ -0,0 +1,159 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Simple deformation controller that restores a mesh to its rest position
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+// This warning tells us about truncation of __long__ stl-generated names.
+// It can occasionally cause DevStudio to have internal compiler warnings.
+#pragma warning( disable : 4786 )
+#endif
+
+#include "RAS_IPolygonMaterial.h"
+#include "BL_MeshDeformer.h"
+#include "BL_SkinMeshObject.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "BLI_arithb.h"
+
+#include "GEN_Map.h"
+#include "STR_HashedString.h"
+
+
+bool BL_MeshDeformer::Apply(RAS_IPolyMaterial *mat)
+{
+ size_t i, j, index;
+ vecVertexArray array;
+ vecIndexArrays mvarray;
+ vecIndexArrays diarray;
+
+ RAS_TexVert *tv;
+ MVert *mvert;
+
+ // For each material
+ array = m_pMeshObject->GetVertexCache(mat);
+ mvarray = m_pMeshObject->GetMVertCache(mat);
+ diarray = m_pMeshObject->GetDIndexCache(mat);
+
+ // For each array
+ for (i=0; i<array.size(); i++){
+ // For each vertex
+ for (j=0; j<array[i]->size(); j++){
+ tv = &((*array[i])[j]);
+ index = ((*diarray[i])[j]);
+
+ mvert = &(m_bmesh->mvert[((*mvarray[i])[index])]);
+ tv->SetXYZ(MT_Point3(mvert->co));
+ }
+ }
+ return true;
+}
+
+BL_MeshDeformer::~BL_MeshDeformer()
+{
+ if (m_transverts)
+ delete []m_transverts;
+ if (m_transnors)
+ delete []m_transnors;
+};
+
+/**
+ * @warning This function is expensive!
+ */
+void BL_MeshDeformer::RecalcNormals()
+{
+ int v, f;
+ float fnor[3], co1[3], co2[3], co3[3], co4[3];
+
+ /* Clear all vertex normal accumulators */
+ for (v =0; v<m_bmesh->totvert; v++){
+ m_transnors[v]=MT_Point3(0,0,0);
+ }
+
+ /* Find the face normals */
+ for (f = 0; f<m_bmesh->totface; f++){
+ // Make new face normal based on the transverts
+ MFace *mf= &((MFace*)m_bmesh->mface)[f];
+
+ if (mf->v3) {
+ for (int vl=0; vl<3; vl++){
+ co1[vl]=m_transverts[mf->v1][vl];
+ co2[vl]=m_transverts[mf->v2][vl];
+ co3[vl]=m_transverts[mf->v3][vl];
+ if (mf->v4)
+ co4[vl]=m_transverts[mf->v4][vl];
+ }
+
+ /* FIXME: Use moto */
+ if (mf->v4)
+ CalcNormFloat4(co1, co2, co3, co4, fnor);
+ else
+ CalcNormFloat(co1, co2, co3, fnor);
+
+ /* Decide which normals are affected by this face's normal */
+ m_transnors[mf->v1]+=MT_Point3(fnor);
+ m_transnors[mf->v2]+=MT_Point3(fnor);
+ m_transnors[mf->v3]+=MT_Point3(fnor);
+ if (mf->v4)
+ m_transnors[mf->v4]+=MT_Point3(fnor);
+ }
+ }
+
+ for (v =0; v<m_bmesh->totvert; v++){
+// float nor[3];
+
+ m_transnors[v]=m_transnors[v].safe_normalized();
+// nor[0]=m_transnors[v][0];
+// nor[1]=m_transnors[v][1];
+// nor[2]=m_transnors[v][2];
+
+ };
+}
+
+void BL_MeshDeformer::VerifyStorage()
+{
+ /* Ensure that we have the right number of verts assigned */
+ if (m_tvtot!=m_bmesh->totvert+m_bmesh->totface){
+ if (m_transverts)
+ delete []m_transverts;
+ if (m_transnors)
+ delete []m_transnors;
+
+ m_transnors =new MT_Point3[m_bmesh->totvert+m_bmesh->totface];
+ m_transverts=new float[(sizeof(*m_transverts)*m_bmesh->totvert)][3];
+ m_tvtot = m_bmesh->totvert;
+ }
+}
+
diff --git a/source/gameengine/Converter/BL_MeshDeformer.h b/source/gameengine/Converter/BL_MeshDeformer.h
new file mode 100644
index 00000000000..adeffd632e7
--- /dev/null
+++ b/source/gameengine/Converter/BL_MeshDeformer.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): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BL_MESHDEFORMER
+#define BL_MESHDEFORMER
+
+#include "RAS_Deformer.h"
+#include "DNA_object_types.h"
+#include "MT_Point3.h"
+#include <stdlib.h>
+
+#ifdef WIN32
+#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
+#endif //WIN32
+
+class BL_MeshDeformer : public RAS_Deformer
+{
+public:
+ void VerifyStorage();
+ void RecalcNormals();
+ virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map){};
+ BL_MeshDeformer(struct Object* obj, class BL_SkinMeshObject *meshobj ):
+ m_pMeshObject(meshobj),
+ m_bmesh((struct Mesh*)(obj->data)),
+ m_objMesh(obj),
+ m_transnors(NULL),
+ m_transverts(NULL),
+ m_tvtot(0)
+ {};
+ virtual ~BL_MeshDeformer();
+ virtual void SetSimulatedTime(double time){};
+ virtual bool Apply(class RAS_IPolyMaterial *mat);
+ virtual void Update(void){};
+ virtual RAS_Deformer* GetReplica(){return NULL;};
+ // virtual void InitDeform(double time){};
+protected:
+ class BL_SkinMeshObject* m_pMeshObject;
+ struct Mesh* m_bmesh;
+ MT_Point3* m_transnors;
+
+ //MT_Point3* m_transverts;
+ // this is so m_transverts doesn't need to be converted
+ // before deformation
+ float (*m_transverts)[3];
+ struct Object* m_objMesh;
+ // --
+ int m_tvtot;
+};
+
+#endif
+
diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp
new file mode 100644
index 00000000000..90b5fc5308d
--- /dev/null
+++ b/source/gameengine/Converter/BL_SkinDeformer.cpp
@@ -0,0 +1,191 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 : 4786)
+#endif //WIN32
+
+#include "BL_SkinDeformer.h"
+#include "GEN_Map.h"
+#include "STR_HashedString.h"
+#include "RAS_IPolygonMaterial.h"
+#include "BL_SkinMeshObject.h"
+
+//#include "BL_ArmatureController.h"
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "BKE_armature.h"
+#include "BKE_action.h"
+#include "MT_Point3.h"
+
+extern "C"{
+ #include "BKE_lattice.h"
+}
+ #include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#define __NLA_DEFNORMALS
+//#undef __NLA_DEFNORMALS
+
+BL_SkinDeformer::~BL_SkinDeformer()
+{
+ if(m_releaseobject && m_armobj)
+ m_armobj->Release();
+};
+
+/* XXX note, this __NLA_OLDDEFORM define seems to be obsolete */
+
+bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat)
+{
+ size_t i, j, index;
+ vecVertexArray array;
+#ifdef __NLA_OLDDEFORM
+ vecMVertArray mvarray;
+#else
+ vecIndexArrays mvarray;
+#endif
+ vecMDVertArray dvarray;
+ vecIndexArrays diarray;
+
+ RAS_TexVert *tv;
+#ifdef __NLA_OLDDEFORM
+ MVert *mvert;
+ MDeformVert *dvert;
+#endif
+ MT_Point3 pt;
+// float co[3];
+
+ if (!m_armobj)
+ return false;
+
+ Update();
+
+ array = m_pMeshObject->GetVertexCache(mat);
+#ifdef __NLA_OLDDEFORM
+ dvarray = m_pMeshObject->GetDVertCache(mat);
+#endif
+ mvarray = m_pMeshObject->GetMVertCache(mat);
+ diarray = m_pMeshObject->GetDIndexCache(mat);
+
+
+ // For each array
+ for (i=0; i<array.size(); i++){
+ // For each vertex
+ for (j=0; j<array[i]->size(); j++){
+
+ tv = &((*array[i])[j]);
+
+ index = ((*diarray[i])[j]);
+#ifdef __NLA_OLDDEFORM
+ pt = tv->xyz();
+ mvert = ((*mvarray[i])[index]);
+ dvert = ((*dvarray[i])[index]);
+#endif
+
+ // Copy the untransformed data from the original mvert
+#ifdef __NLA_OLDDEFORM
+ co[0]=mvert->co[0];
+ co[1]=mvert->co[1];
+ co[2]=mvert->co[2];
+
+ // Do the deformation
+/* XXX note, doesnt exist anymore */
+// GB_calc_armature_deform(co, dvert);
+ tv->SetXYZ(co);
+#else
+ // Set the data
+ tv->SetXYZ(m_transverts[((*mvarray[i])[index])]);
+#ifdef __NLA_DEFNORMALS
+
+ tv->SetNormal(m_transnors[((*mvarray[i])[index])]);
+#endif
+#endif
+ }
+ }
+
+ return true;
+}
+
+RAS_Deformer *BL_SkinDeformer::GetReplica()
+{
+ BL_SkinDeformer *result;
+
+ result = new BL_SkinDeformer(*this);
+ result->ProcessReplica();
+ return result;
+}
+
+void BL_SkinDeformer::ProcessReplica()
+{
+}
+
+//void where_is_pose (Object *ob);
+//void armature_deform_verts(Object *armOb, Object *target, float (*vertexCos)[3], int numVerts, int deformflag);
+void BL_SkinDeformer::Update(void)
+{
+ /* See if the armature has been updated for this frame */
+ if (m_lastUpdate!=m_armobj->GetLastFrame()){
+
+ /* Do all of the posing necessary */
+ m_armobj->ApplyPose();
+
+ /* XXX note: where_is_pose() (from BKE_armature.h) calculates all matrices needed to start deforming */
+ /* but it requires the blender object pointer... */
+
+ Object* par_arma = m_armobj->GetArmatureObject();
+ where_is_pose( par_arma );
+
+ /* store verts locally */
+ VerifyStorage();
+
+ /* duplicate */
+ for (int v =0; v<m_bmesh->totvert; v++)
+ VECCOPY(m_transverts[v], m_bmesh->mvert[v].co);
+
+ armature_deform_verts( par_arma, m_objMesh, NULL, m_transverts, NULL, m_bmesh->totvert, ARM_DEF_VGROUP, NULL );
+ RecalcNormals();
+
+ /* Update the current frame */
+ m_lastUpdate=m_armobj->GetLastFrame();
+ }
+}
+
+/* XXX note: I propose to drop this function */
+void BL_SkinDeformer::SetArmature(BL_ArmatureObject *armobj)
+{
+ // only used to set the object now
+ m_armobj = armobj;
+}
diff --git a/source/gameengine/Converter/BL_SkinDeformer.h b/source/gameengine/Converter/BL_SkinDeformer.h
new file mode 100644
index 00000000000..74adc6c2943
--- /dev/null
+++ b/source/gameengine/Converter/BL_SkinDeformer.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 *****
+ */
+
+#ifndef BL_SKINDEFORMER
+#define BL_SKINDEFORMER
+
+#ifdef WIN32
+#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
+#endif //WIN32
+
+#include "GEN_HashedPtr.h"
+#include "BL_MeshDeformer.h"
+#include "BL_ArmatureObject.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "BKE_armature.h"
+
+#include "RAS_Deformer.h"
+
+
+class BL_SkinDeformer : public BL_MeshDeformer
+{
+public:
+// void SetArmatureController (BL_ArmatureController *cont);
+ virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map)
+ {
+ void **h_obj = (*map)[m_armobj];
+ if (h_obj){
+ SetArmature( (BL_ArmatureObject*)(*h_obj) );
+ }
+ else
+ m_armobj=NULL;
+ }
+ void SetArmature (class BL_ArmatureObject *armobj);
+
+ BL_SkinDeformer(struct Object *bmeshobj,
+ class BL_SkinMeshObject *mesh,
+ BL_ArmatureObject* arma = NULL)
+ : //
+ BL_MeshDeformer(bmeshobj, mesh),
+ m_armobj(arma),
+ m_lastUpdate(-1),
+ m_defbase(&bmeshobj->defbase),
+ m_releaseobject(false)
+ {
+ };
+
+ /* this second constructor is needed for making a mesh deformable on the fly. */
+ BL_SkinDeformer(struct Object *bmeshobj_old,
+ struct Object *bmeshobj_new,
+ class BL_SkinMeshObject *mesh,
+ bool release_object,
+ BL_ArmatureObject* arma = NULL)
+ : //
+ BL_MeshDeformer(bmeshobj_old, mesh),
+ m_armobj(arma),
+ m_lastUpdate(-1),
+ m_defbase(&bmeshobj_old->defbase),
+ m_releaseobject(release_object)
+ {
+ };
+
+ virtual void ProcessReplica();
+ virtual RAS_Deformer *GetReplica();
+ virtual ~BL_SkinDeformer();
+ void Update (void);
+ bool Apply (class RAS_IPolyMaterial *polymat);
+
+protected:
+ BL_ArmatureObject* m_armobj; // Our parent object
+ float m_time;
+ double m_lastUpdate;
+ ListBase* m_defbase;
+ bool m_releaseobject;
+
+};
+
+#endif
+
diff --git a/source/gameengine/Converter/BL_SkinMeshObject.cpp b/source/gameengine/Converter/BL_SkinMeshObject.cpp
new file mode 100644
index 00000000000..364fd76776f
--- /dev/null
+++ b/source/gameengine/Converter/BL_SkinMeshObject.cpp
@@ -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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Deformer that supports armature skinning
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
+#endif //WIN32
+#include "RAS_IPolygonMaterial.h"
+#include "BL_SkinMeshObject.h"
+#include "BL_DeformableGameObject.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "KX_GameObject.h"
+#include "RAS_BucketManager.h"
+
+void BL_SkinMeshObject::AddPolygon(RAS_Polygon* poly)
+{
+ /* We're overriding this so that we can eventually associate faces with verts somehow */
+
+ // For vertIndex in poly:
+ // find the appropriate normal
+
+ RAS_MeshObject::AddPolygon(poly);
+}
+
+#ifdef __NLA_OLDDEFORM
+int BL_SkinMeshObject::FindOrAddDeform(int vtxarray, struct MVert *mv, struct MDeformVert *dv, RAS_IPolyMaterial* mat)
+#else
+int BL_SkinMeshObject::FindOrAddDeform(unsigned int vtxarray, unsigned int mv, struct MDeformVert *dv, RAS_IPolyMaterial* mat)
+#endif
+{
+ BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
+ int numvert = ao->m_MvertArrayCache1[vtxarray]->size();
+
+ /* Check to see if this has already been pushed */
+ for (unsigned int i=0; i<ao->m_MvertArrayCache1[vtxarray]->size(); i++){
+ if (mv == (*ao->m_MvertArrayCache1[vtxarray])[i])
+ return i;
+ }
+
+ ao->m_MvertArrayCache1[vtxarray]->push_back(mv);
+ ao->m_DvertArrayCache1[vtxarray]->push_back(dv);
+
+ return numvert;
+};
+
+int BL_SkinMeshObject::FindVertexArray(int numverts,RAS_IPolyMaterial* polymat)
+{
+ int array=-1;
+
+ BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(polymat);
+
+
+ for (size_t i=0;i<ao->m_VertexArrayCache1.size();i++)
+ {
+ if ( (ao->m_TriangleArrayCount[i] + (numverts-2)) < BUCKET_MAX_TRIANGLES)
+ {
+ if((ao->m_VertexArrayCache1[i]->size()+numverts < BUCKET_MAX_INDICES))
+ {
+ array = i;
+ ao->m_TriangleArrayCount[array]+=numverts-2;
+ break;
+ }
+ }
+ }
+
+
+ if (array == -1)
+ {
+ array = ao->m_VertexArrayCache1.size();
+
+ vector<RAS_TexVert>* va = new vector<RAS_TexVert>;
+ ao->m_VertexArrayCache1.push_back(va);
+
+ KX_IndexArray *ia = new KX_IndexArray();
+ ao->m_IndexArrayCache1.push_back(ia);
+
+#ifdef __NLA_OLDDEFORM
+ BL_MVertArray *bva = new BL_MVertArray();
+#else
+ KX_IndexArray *bva = new KX_IndexArray();
+#endif
+ ao->m_MvertArrayCache1.push_back(bva);
+
+ BL_DeformVertArray *dva = new BL_DeformVertArray();
+ ao->m_DvertArrayCache1.push_back(dva);
+
+ KX_IndexArray *da = new KX_IndexArray();
+ ao->m_DIndexArrayCache1.push_back(da);
+
+ ao->m_TriangleArrayCount.push_back(numverts-2);
+
+ }
+
+
+ return array;
+}
+
+
+//void BL_SkinMeshObject::Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec,RAS_BucketManager* bucketmgr)
+void BL_SkinMeshObject::Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec)
+{
+
+ KX_MeshSlot ms;
+ ms.m_clientObj = clientobj;
+ ms.m_mesh = this;
+ ms.m_OpenGLMatrix = oglmatrix;
+ ms.m_bObjectColor = useObjectColor;
+ ms.m_RGBAcolor = rgbavec;
+ ms.m_pDeformer = ((BL_DeformableGameObject*)clientobj)->m_pDeformer;
+
+ for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();it++)
+ {
+
+ RAS_MaterialBucket* materialbucket = (*it);
+
+// KX_ArrayOptimizer* oa = GetArrayOptimizer(materialbucket->GetPolyMaterial());
+ materialbucket->SetMeshSlot(ms);
+ }
+
+}
+
+
+
diff --git a/source/gameengine/Converter/BL_SkinMeshObject.h b/source/gameengine/Converter/BL_SkinMeshObject.h
new file mode 100644
index 00000000000..1d02dd1ceb4
--- /dev/null
+++ b/source/gameengine/Converter/BL_SkinMeshObject.h
@@ -0,0 +1,181 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __BL_SKINMESHOBJECT
+#define __BL_SKINMESHOBJECT
+
+#ifdef WIN32
+#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
+#endif //WIN32
+
+#include "RAS_MeshObject.h"
+#include "RAS_Deformer.h"
+#include "RAS_IPolygonMaterial.h"
+
+#include "BL_MeshDeformer.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+typedef vector<struct MVert*> BL_MVertArray;
+typedef vector<struct MDeformVert*> BL_DeformVertArray;
+typedef vector<class BL_TexVert> BL_VertexArray;
+
+
+typedef vector<vector<struct MDeformVert*>*> vecMDVertArray;
+typedef vector<vector<class BL_TexVert>*> vecBVertexArray;
+
+class BL_SkinArrayOptimizer : public KX_ArrayOptimizer
+{
+public:
+ BL_SkinArrayOptimizer(int index)
+ :KX_ArrayOptimizer (index) {};
+ virtual ~BL_SkinArrayOptimizer(){
+
+ for (vector<KX_IndexArray*>::iterator itv = m_MvertArrayCache1.begin();
+ !(itv == m_MvertArrayCache1.end());itv++)
+ {
+ delete (*itv);
+ }
+ for (vector<BL_DeformVertArray*>::iterator itd = m_DvertArrayCache1.begin();
+ !(itd == m_DvertArrayCache1.end());itd++)
+ {
+ delete (*itd);
+ }
+ for (vector<KX_IndexArray*>::iterator iti = m_DIndexArrayCache1.begin();
+ !(iti == m_DIndexArrayCache1.end());iti++)
+ {
+ delete (*iti);
+ }
+
+ m_MvertArrayCache1.clear();
+ m_DvertArrayCache1.clear();
+ m_DIndexArrayCache1.clear();
+ };
+
+ vector<KX_IndexArray*> m_MvertArrayCache1;
+ vector<BL_DeformVertArray*> m_DvertArrayCache1;
+ vector<KX_IndexArray*> m_DIndexArrayCache1;
+
+};
+
+class BL_SkinMeshObject : public RAS_MeshObject
+{
+
+// enum { BUCKET_MAX_INDICES = 16384};//2048};//8192};
+// enum { BUCKET_MAX_TRIANGLES = 4096};
+
+ KX_ArrayOptimizer* GetArrayOptimizer(RAS_IPolyMaterial* polymat)
+ {
+ KX_ArrayOptimizer** aop = (m_matVertexArrayS[*polymat]);
+ if (aop)
+ return *aop;
+ int numelements = m_matVertexArrayS.size();
+ m_sortedMaterials.push_back(polymat);
+
+ BL_SkinArrayOptimizer* ao = new BL_SkinArrayOptimizer(numelements);
+ m_matVertexArrayS.insert(*polymat,ao);
+ return ao;
+ }
+
+protected:
+public:
+ void Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec);
+// void Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec,class RAS_BucketManager* bucketmgr);
+
+ int FindVertexArray(int numverts,RAS_IPolyMaterial* polymat);
+ BL_SkinMeshObject(int lightlayer) : RAS_MeshObject (lightlayer)
+ { m_class = 1;};
+
+ virtual ~BL_SkinMeshObject(){
+ };
+
+ const vecIndexArrays& GetDIndexCache (RAS_IPolyMaterial* mat)
+ {
+ BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
+ return ao->m_DIndexArrayCache1;
+ }
+ const vecMDVertArray& GetDVertCache (RAS_IPolyMaterial* mat)
+ {
+ BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
+ return ao->m_DvertArrayCache1;
+ }
+ const vecIndexArrays& GetMVertCache (RAS_IPolyMaterial* mat)
+ {
+ BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
+ return ao->m_MvertArrayCache1;
+ }
+
+ void AddPolygon(RAS_Polygon* poly);
+ int FindOrAddDeform(unsigned int vtxarray, unsigned int mv, struct MDeformVert *dv, RAS_IPolyMaterial* mat);
+ int FindOrAddVertex(int vtxarray,const MT_Point3& xyz,
+ const MT_Point2& uv,
+ const MT_Point2& uv2,
+ const MT_Vector4& tangent,
+ const unsigned int rgbacolor,
+ const MT_Vector3& normal, int defnr, bool flat, RAS_IPolyMaterial* mat)
+ {
+ RAS_TexVert tempvert(xyz,uv,uv2, tangent,rgbacolor,normal,flat ? TV_CALCFACENORMAL : 0);
+
+ // KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
+ BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
+
+ int numverts = ao->m_VertexArrayCache1[vtxarray]->size();//m_VertexArrayCount[vtxarray];
+
+ int index=-1;
+
+ for (int i=0;i<numverts;i++)
+ {
+ const RAS_TexVert& vtx = (*ao->m_VertexArrayCache1[vtxarray])[i];
+ if (tempvert.closeTo(&vtx))
+ {
+ index = i;
+ break;
+ }
+
+ }
+ if (index >= 0)
+ return index;
+
+ // no vertex found, add one
+ ao->m_VertexArrayCache1[vtxarray]->push_back(tempvert);
+ ao->m_DIndexArrayCache1[vtxarray]->push_back(defnr);
+
+ return numverts;
+
+
+ }
+
+};
+
+#endif
+
diff --git a/source/gameengine/Converter/BlenderWorldInfo.cpp b/source/gameengine/Converter/BlenderWorldInfo.cpp
new file mode 100644
index 00000000000..eb03a3c2a38
--- /dev/null
+++ b/source/gameengine/Converter/BlenderWorldInfo.cpp
@@ -0,0 +1,237 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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> // printf()
+
+#include "BlenderWorldInfo.h"
+#include "KX_BlenderGL.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* This little block needed for linking to Blender... */
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+/* This list includes only data type definitions */
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_group_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_property_types.h"
+#include "DNA_text_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_actuator_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_global.h"
+/* end of blender include block */
+
+
+BlenderWorldInfo::BlenderWorldInfo(struct World* blenderworld)
+{
+ if (blenderworld)
+ {
+ m_hasworld = true;
+
+ // do we have mist?
+ if ((blenderworld->mode) & WO_MIST)
+ {
+ m_hasmist = true;
+ m_miststart = blenderworld->miststa;
+ m_mistdistance = blenderworld->mistdist;
+ m_mistred = blenderworld->horr;
+ m_mistgreen = blenderworld->horg;
+ m_mistblue = blenderworld->horb;
+ }
+ else
+ {
+ m_hasmist = false;
+ m_miststart = 0.0;
+ m_mistdistance = 0.0;
+ m_mistred = 0.0;
+ m_mistgreen = 0.0;
+ m_mistblue = 0.0;
+ }
+
+ m_backgroundred = blenderworld->horr;
+ m_backgroundgreen = blenderworld->horg;
+ m_backgroundblue = blenderworld->horb;
+
+ m_ambientred = blenderworld->ambr;
+ m_ambientgreen = blenderworld->ambg;
+ m_ambientblue = blenderworld->ambb;
+ }
+ else
+ {
+ m_hasworld = false;
+ }
+}
+
+
+
+BlenderWorldInfo::~BlenderWorldInfo()
+{
+
+}
+
+
+bool BlenderWorldInfo::hasWorld()
+{
+ return m_hasworld;
+}
+
+
+
+bool BlenderWorldInfo::hasMist()
+{
+ return m_hasmist;
+}
+
+
+
+float BlenderWorldInfo::getBackColorRed()
+{
+ return m_backgroundred;
+}
+
+
+
+float BlenderWorldInfo::getBackColorGreen()
+{
+ return m_backgroundgreen;
+}
+
+
+
+float BlenderWorldInfo::getBackColorBlue()
+{
+ return m_backgroundblue;
+}
+
+
+float BlenderWorldInfo::getAmbientColorRed()
+{
+ return m_ambientred;
+}
+
+float BlenderWorldInfo::getAmbientColorGreen()
+{
+ return m_ambientgreen;
+}
+
+float BlenderWorldInfo::getAmbientColorBlue()
+{
+ return m_ambientblue;
+}
+
+float BlenderWorldInfo::getMistStart()
+{
+ return m_miststart;
+}
+
+
+
+float BlenderWorldInfo::getMistDistance()
+{
+ return m_mistdistance;
+}
+
+
+
+float BlenderWorldInfo::getMistColorRed()
+{
+ return m_mistred;
+}
+
+
+
+float BlenderWorldInfo::getMistColorGreen()
+{
+ return m_mistgreen;
+}
+
+
+
+float BlenderWorldInfo::getMistColorBlue()
+{
+ return m_mistblue;
+}
+
+
+ void
+BlenderWorldInfo::setMistStart(
+ float d
+) {
+ m_miststart = d;
+}
+
+
+ void
+BlenderWorldInfo::setMistDistance(
+ float d
+) {
+ m_mistdistance = d;
+}
+
+
+ void
+BlenderWorldInfo::setMistColorRed(
+ float d
+) {
+ m_mistred = d;
+}
+
+
+ void
+BlenderWorldInfo::setMistColorGreen(
+ float d
+) {
+ m_mistgreen = d;
+}
+
+
+ void
+BlenderWorldInfo::setMistColorBlue(
+ float d
+) {
+ m_mistblue = d;
+}
diff --git a/source/gameengine/Converter/BlenderWorldInfo.h b/source/gameengine/Converter/BlenderWorldInfo.h
new file mode 100644
index 00000000000..35e47bbf9b8
--- /dev/null
+++ b/source/gameengine/Converter/BlenderWorldInfo.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 __BLENDERWORLDINFO_H
+#define __BLENDERWORLDINFO_H
+#include "MT_CmMatrix4x4.h"
+#include "KX_WorldInfo.h"
+#include "KX_BlenderGL.h"
+
+class BlenderWorldInfo : public KX_WorldInfo
+{
+ bool m_hasworld;
+ float m_backgroundred;
+ float m_backgroundgreen;
+ float m_backgroundblue;
+
+ bool m_hasmist;
+ float m_miststart;
+ float m_mistdistance;
+ float m_mistred;
+ float m_mistgreen;
+ float m_mistblue;
+
+ float m_ambientred;
+ float m_ambientgreen;
+ float m_ambientblue;
+
+public:
+ BlenderWorldInfo(struct World* blenderworld);
+ ~BlenderWorldInfo();
+
+ bool hasWorld();
+ bool hasMist();
+ float getBackColorRed();
+ float getBackColorGreen();
+ float getBackColorBlue();
+
+ float getAmbientColorRed();
+ float getAmbientColorGreen();
+ float getAmbientColorBlue();
+
+ float getMistStart();
+ float getMistDistance();
+ float getMistColorRed();
+ float getMistColorGreen();
+ float getMistColorBlue();
+
+ void
+ setMistStart(
+ float d
+ );
+
+ void
+ setMistDistance(
+ float d
+ );
+
+ void
+ setMistColorRed(
+ float d
+ );
+
+ void
+ setMistColorGreen(
+ float d
+ );
+
+ void
+ setMistColorBlue(
+ float d
+ );
+};
+
+#endif //__BLENDERWORLDINFO_H
+
diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt
new file mode 100644
index 00000000000..db516b20df2
--- /dev/null
+++ b/source/gameengine/Converter/CMakeLists.txt
@@ -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) 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 *.cpp)
+
+SET(INC
+ .
+ ../../../source/kernel/gen_system
+ ../../../intern/string
+ ../../../intern/guardedalloc
+ ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer
+ ../../../intern/bmfont
+ ../../../intern/SoundSystem
+ ../../../intern/SoundSystem/include
+ ../../../intern/SoundSystem/openal
+ ../../../intern/SoundSystem/dummy
+ ../../../intern/SoundSystem/intern
+ ../../../source/gameengine/Converter
+ ../../../source/gameengine/BlenderRoutines
+ ../../../source/blender/imbuf
+ ../../../intern/moto/include
+ ../../../source/gameengine/Ketsji
+ ../../../source/gameengine/Ketsji/KXNetwork
+ ../../../source/blender/blenlib
+ ../../../source/blender/blenkernel
+ ../../../source/blender
+ ../../../source/blender/include
+ ../../../source/blender/makesdna
+ ../../../source/gameengine/Rasterizer
+ ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer
+ ../../../source/gameengine/GameLogic
+ ../../../source/gameengine/Expressions
+ ../../../source/gameengine/Network
+ ../../../source/gameengine/SceneGraph
+ ../../../source/gameengine/Physics/common
+ ../../../source/gameengine/Physics/Bullet
+ ../../../source/gameengine/Physics/BlOde
+ ../../../source/gameengine/Physics/Dummy
+ ../../../source/gameengine/Physics/Sumo
+ ../../../source/gameengine/Physics/Sumo/Fuzzics/include
+ ../../../source/gameengine/Network/LoopBackNetwork
+ ../../../source/blender/misc
+ ../../../source/blender/blenloader
+ ../../../extern/bullet2/src
+ ../../../extern/solid
+ ${PYTHON_INC}
+)
+
+BLENDERLIB(bf_converter "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_converter', sources, Split(incs), [], libtype=['game','player'], priority=[5,70] )
diff --git a/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp b/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp
new file mode 100644
index 00000000000..8722f90f456
--- /dev/null
+++ b/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp
@@ -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 *****
+ */
+
+#include "KX_BlenderScalarInterpolator.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+extern "C" int IPO_GetChannels(struct Ipo *ipo, short *channels);
+extern "C" float IPO_GetFloatValue(struct Ipo *ipo, /*IPO_Channel*/ short channel, float ctime);
+
+
+static const int BL_MAX_CHANNELS = 32;
+
+float BL_ScalarInterpolator::GetValue(float currentTime) const {
+ return IPO_GetFloatValue(m_blender_ipo, m_channel, currentTime);
+}
+
+typedef short IPO_Channel;
+
+BL_InterpolatorList::BL_InterpolatorList(struct Ipo *ipo) {
+ IPO_Channel channels[BL_MAX_CHANNELS];
+
+ int num_channels = IPO_GetChannels(ipo, channels);
+
+ int i;
+
+ for (i = 0; i != num_channels; ++i) {
+ BL_ScalarInterpolator *new_ipo =
+ new BL_ScalarInterpolator(ipo, channels[i]);
+
+ //assert(new_ipo);
+ push_back(new_ipo);
+ }
+}
+
+BL_InterpolatorList::~BL_InterpolatorList() {
+ BL_InterpolatorList::iterator i;
+ for (i = begin(); !(i == end()); ++i) {
+ delete *i;
+ }
+}
+
+
+KX_IScalarInterpolator *BL_InterpolatorList::GetScalarInterpolator(BL_IpoChannel channel) {
+ BL_InterpolatorList::iterator i = begin();
+ while (!(i == end()) &&
+ (static_cast<BL_ScalarInterpolator *>(*i))->GetChannel() !=
+ channel) {
+ ++i;
+ }
+
+ return (i == end()) ? 0 : *i;
+}
+
diff --git a/source/gameengine/Converter/KX_BlenderScalarInterpolator.h b/source/gameengine/Converter/KX_BlenderScalarInterpolator.h
new file mode 100644
index 00000000000..fd9cfcb04ce
--- /dev/null
+++ b/source/gameengine/Converter/KX_BlenderScalarInterpolator.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 __KX_SCALARINTERPOLATOR_H
+#define __KX_SCALARINTERPOLATOR_H
+
+#include <vector>
+
+#include "KX_IScalarInterpolator.h"
+
+typedef unsigned short BL_IpoChannel;
+
+class BL_ScalarInterpolator : public KX_IScalarInterpolator {
+public:
+ BL_ScalarInterpolator() {} // required for use in STL list
+ BL_ScalarInterpolator(struct Ipo *ipo, BL_IpoChannel channel) :
+ m_blender_ipo(ipo),
+ m_channel(channel)
+ {}
+
+ virtual ~BL_ScalarInterpolator() {}
+
+ virtual float GetValue(float currentTime) const;
+
+ BL_IpoChannel GetChannel() const { return m_channel; }
+
+private:
+ struct Ipo *m_blender_ipo;
+ BL_IpoChannel m_channel;
+};
+
+
+class BL_InterpolatorList : public std::vector<KX_IScalarInterpolator *> {
+public:
+ BL_InterpolatorList(struct Ipo *ipo);
+ ~BL_InterpolatorList();
+
+ KX_IScalarInterpolator *GetScalarInterpolator(BL_IpoChannel channel);
+};
+
+#endif //__KX_SCALARINTERPOLATOR_H
+
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
new file mode 100644
index 00000000000..47d8f186653
--- /dev/null
+++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
@@ -0,0 +1,993 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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:4786) // suppress stl-MSVC debug info warning
+#endif
+
+#include "KX_Scene.h"
+#include "KX_GameObject.h"
+#include "KX_BlenderSceneConverter.h"
+#include "KX_IpoConvert.h"
+#include "RAS_MeshObject.h"
+#include "KX_PhysicsEngineEnums.h"
+#include "PHY_IPhysicsEnvironment.h"
+#include "KX_KetsjiEngine.h"
+#include "KX_IPhysicsController.h"
+#include "BL_Material.h"
+#include "SYS_System.h"
+
+#include "DummyPhysicsEnvironment.h"
+
+//to decide to use sumo/ode or dummy physics - defines USE_ODE
+#include "KX_ConvertPhysicsObject.h"
+
+#ifdef USE_BULLET
+#include "CcdPhysicsEnvironment.h"
+#endif
+
+#ifdef USE_ODE
+#include "OdePhysicsEnvironment.h"
+#endif //USE_ODE
+
+#ifdef USE_SUMO_SOLID
+#include "SumoPhysicsEnvironment.h"
+#endif
+
+#include "KX_BlenderSceneConverter.h"
+#include "KX_BlenderScalarInterpolator.h"
+#include "BL_BlenderDataConversion.h"
+#include "BlenderWorldInfo.h"
+#include "KX_Scene.h"
+
+/* This little block needed for linking to Blender... */
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+/* This list includes only data type definitions */
+#include "DNA_scene_types.h"
+#include "DNA_world_types.h"
+#include "BKE_main.h"
+
+#include "BLI_arithb.h"
+
+extern "C"
+{
+#include "DNA_object_types.h"
+#include "DNA_curve_types.h"
+#include "BLI_blenlib.h"
+#include "MEM_guardedalloc.h"
+#include "BSE_editipo.h"
+#include "BSE_editipo_types.h"
+#include "DNA_ipo_types.h"
+#include "BKE_global.h"
+#include "DNA_space_types.h"
+}
+
+
+KX_BlenderSceneConverter::KX_BlenderSceneConverter(
+ struct Main* maggie,
+ struct SpaceIpo* sipo,
+ class KX_KetsjiEngine* engine
+ )
+ : m_maggie(maggie),
+ m_sipo(sipo),
+ m_ketsjiEngine(engine),
+ m_alwaysUseExpandFraming(false),
+ m_usemat(false)
+{
+ m_newfilename = "";
+}
+
+
+KX_BlenderSceneConverter::~KX_BlenderSceneConverter()
+{
+ // clears meshes, and hashmaps from blender to gameengine data
+ int i;
+ // delete sumoshapes
+
+
+ int numipolists = m_map_blender_to_gameipolist.size();
+ for (i=0; i<numipolists; i++) {
+ BL_InterpolatorList *ipoList= *m_map_blender_to_gameipolist.at(i);
+
+ delete (ipoList);
+ }
+
+ vector<KX_WorldInfo*>::iterator itw = m_worldinfos.begin();
+ while (itw != m_worldinfos.end()) {
+ delete (*itw);
+ itw++;
+ }
+
+ vector<RAS_IPolyMaterial*>::iterator itp = m_polymaterials.begin();
+ while (itp != m_polymaterials.end()) {
+ delete (*itp);
+ itp++;
+ }
+
+ // delete after RAS_IPolyMaterial
+ vector<BL_Material *>::iterator itmat = m_materials.begin();
+ while (itmat != m_materials.end()) {
+ delete (*itmat);
+ itmat++;
+ }
+
+
+ vector<RAS_MeshObject*>::iterator itm = m_meshobjects.begin();
+ while (itm != m_meshobjects.end()) {
+ delete (*itm);
+ itm++;
+ }
+
+#ifdef USE_SUMO_SOLID
+ KX_ClearSumoSharedShapes();
+#endif
+
+#ifdef USE_BULLET
+ KX_ClearBulletSharedShapes();
+#endif
+
+}
+
+
+
+void KX_BlenderSceneConverter::SetNewFileName(const STR_String& filename)
+{
+ m_newfilename = filename;
+}
+
+
+
+bool KX_BlenderSceneConverter::TryAndLoadNewFile()
+{
+ bool result = false;
+
+ // find the file
+/* if ()
+ {
+ result = true;
+ }
+ // if not, clear the newfilename
+ else
+ {
+ m_newfilename = "";
+ }
+*/
+ return result;
+}
+
+
+
+ /**
+ * Find the specified scene by name, or the first
+ * scene if nothing matches (shouldn't happen).
+ */
+static struct Scene *GetSceneForName2(struct Main *maggie, const STR_String& scenename) {
+ Scene *sce;
+
+ for (sce= (Scene*) maggie->scene.first; sce; sce= (Scene*) sce->id.next)
+ if (scenename == (sce->id.name+2))
+ return sce;
+
+ return (Scene*) maggie->scene.first;
+}
+#include "KX_PythonInit.h"
+
+#ifdef USE_BULLET
+
+#include "LinearMath/btIDebugDraw.h"
+
+
+struct BlenderDebugDraw : public btIDebugDraw
+{
+ BlenderDebugDraw () :
+ m_debugMode(0)
+ {
+ }
+
+ int m_debugMode;
+
+ virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color)
+ {
+ if (m_debugMode >0)
+ {
+ MT_Vector3 kxfrom(from[0],from[1],from[2]);
+ MT_Vector3 kxto(to[0],to[1],to[2]);
+ MT_Vector3 kxcolor(color[0],color[1],color[2]);
+
+ KX_RasterizerDrawDebugLine(kxfrom,kxto,kxcolor);
+ }
+ }
+
+ virtual void reportErrorWarning(const char* warningString)
+ {
+
+ }
+
+ virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,float distance,int lifeTime,const btVector3& color)
+ {
+ //not yet
+ }
+
+ virtual void setDebugMode(int debugMode)
+ {
+ m_debugMode = debugMode;
+ }
+ virtual int getDebugMode() const
+ {
+ return m_debugMode;
+ }
+
+};
+
+#endif
+
+void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename,
+ class KX_Scene* destinationscene,
+ PyObject* dictobj,
+ class SCA_IInputDevice* keyinputdev,
+ class RAS_IRenderTools* rendertools,
+ class RAS_ICanvas* canvas)
+{
+ //find out which physics engine
+ Scene *blenderscene = GetSceneForName2(m_maggie, scenename);
+
+ e_PhysicsEngine physics_engine = UseBullet;
+
+ if (blenderscene)
+ {
+
+ if (blenderscene->world)
+ {
+ switch (blenderscene->world->physicsEngine)
+ {
+ case WOPHY_BULLET:
+ {
+ physics_engine = UseBullet;
+ break;
+ }
+
+ case WOPHY_ODE:
+ {
+ physics_engine = UseODE;
+ break;
+ }
+ case WOPHY_DYNAMO:
+ {
+ physics_engine = UseDynamo;
+ break;
+ }
+ case WOPHY_SUMO:
+ {
+ physics_engine = UseSumo;
+ break;
+ }
+ case WOPHY_NONE:
+ {
+ physics_engine = UseNone;
+ }
+ }
+
+ }
+ }
+
+ switch (physics_engine)
+ {
+#ifdef USE_BULLET
+ case UseBullet:
+ {
+ CcdPhysicsEnvironment* ccdPhysEnv = new CcdPhysicsEnvironment();
+ ccdPhysEnv->setDebugDrawer(new BlenderDebugDraw());
+ ccdPhysEnv->setDeactivationLinearTreshold(0.8f); // default, can be overridden by Python
+ ccdPhysEnv->setDeactivationAngularTreshold(1.0f); // default, can be overridden by Python
+
+ SYS_SystemHandle syshandle = SYS_GetSystem(); /*unused*/
+ int visualizePhysics = SYS_GetCommandLineInt(syshandle,"show_physics",0);
+ if (visualizePhysics)
+ ccdPhysEnv->setDebugMode(btIDebugDraw::DBG_DrawWireframe|btIDebugDraw::DBG_DrawAabb|btIDebugDraw::DBG_DrawContactPoints|btIDebugDraw::DBG_DrawText);
+
+ //todo: get a button in blender ?
+ //disable / enable debug drawing (contact points, aabb's etc)
+ //ccdPhysEnv->setDebugMode(1);
+ destinationscene->SetPhysicsEnvironment(ccdPhysEnv);
+ break;
+ }
+#endif
+
+#ifdef USE_SUMO_SOLID
+ case UseSumo:
+ destinationscene ->SetPhysicsEnvironment(new SumoPhysicsEnvironment());
+ break;
+#endif
+#ifdef USE_ODE
+
+ case UseODE:
+ destinationscene ->SetPhysicsEnvironment(new ODEPhysicsEnvironment());
+ break;
+#endif //USE_ODE
+
+ case UseDynamo:
+ {
+ }
+
+ default:
+ case UseNone:
+ physics_engine = UseNone;
+ destinationscene ->SetPhysicsEnvironment(new DummyPhysicsEnvironment());
+ break;
+ }
+
+ BL_ConvertBlenderObjects(m_maggie,
+ scenename,
+ destinationscene,
+ m_ketsjiEngine,
+ physics_engine,
+ dictobj,
+ keyinputdev,
+ rendertools,
+ canvas,
+ this,
+ m_alwaysUseExpandFraming
+ );
+
+ m_map_blender_to_gameactuator.clear();
+ m_map_blender_to_gamecontroller.clear();
+
+ m_map_blender_to_gameobject.clear();
+ m_map_mesh_to_gamemesh.clear();
+
+ //don't clear it yet, it is needed for the baking physics into ipo animation
+ //m_map_gameobject_to_blender.clear();
+}
+
+
+// use blender materials
+void KX_BlenderSceneConverter::SetMaterials(bool val)
+{
+ m_usemat = val;
+}
+
+bool KX_BlenderSceneConverter::GetMaterials()
+{
+ return m_usemat;
+}
+
+
+void KX_BlenderSceneConverter::RegisterBlenderMaterial(BL_Material *mat)
+{
+ m_materials.push_back(mat);
+}
+
+
+
+void KX_BlenderSceneConverter::SetAlwaysUseExpandFraming(
+ bool to_what)
+{
+ m_alwaysUseExpandFraming= to_what;
+}
+
+
+
+void KX_BlenderSceneConverter::RegisterGameObject(
+ KX_GameObject *gameobject,
+ struct Object *for_blenderobject)
+{
+ m_map_gameobject_to_blender.insert(CHashedPtr(gameobject),for_blenderobject);
+ m_map_blender_to_gameobject.insert(CHashedPtr(for_blenderobject),gameobject);
+}
+
+
+
+KX_GameObject *KX_BlenderSceneConverter::FindGameObject(
+ struct Object *for_blenderobject)
+{
+ KX_GameObject **obp= m_map_blender_to_gameobject[CHashedPtr(for_blenderobject)];
+
+ return obp?*obp:NULL;
+}
+
+
+
+struct Object *KX_BlenderSceneConverter::FindBlenderObject(
+ KX_GameObject *for_gameobject)
+{
+ struct Object **obp= m_map_gameobject_to_blender[CHashedPtr(for_gameobject)];
+
+ return obp?*obp:NULL;
+}
+
+
+
+void KX_BlenderSceneConverter::RegisterGameMesh(
+ RAS_MeshObject *gamemesh,
+ struct Mesh *for_blendermesh)
+{
+ m_map_mesh_to_gamemesh.insert(CHashedPtr(for_blendermesh),gamemesh);
+ m_meshobjects.push_back(gamemesh);
+}
+
+
+
+RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh(
+ struct Mesh *for_blendermesh,
+ unsigned int onlayer)
+{
+ RAS_MeshObject** meshp = m_map_mesh_to_gamemesh[CHashedPtr(for_blendermesh)];
+
+ if (meshp && onlayer==(*meshp)->GetLightLayer()) {
+ return *meshp;
+ } else {
+ return NULL;
+ }
+}
+
+
+
+
+
+
+void KX_BlenderSceneConverter::RegisterPolyMaterial(RAS_IPolyMaterial *polymat)
+{
+ m_polymaterials.push_back(polymat);
+}
+
+
+
+void KX_BlenderSceneConverter::RegisterInterpolatorList(
+ BL_InterpolatorList *ipoList,
+ struct Ipo *for_ipo)
+{
+ m_map_blender_to_gameipolist.insert(CHashedPtr(for_ipo), ipoList);
+}
+
+
+
+BL_InterpolatorList *KX_BlenderSceneConverter::FindInterpolatorList(
+ struct Ipo *for_ipo)
+{
+ BL_InterpolatorList **listp = m_map_blender_to_gameipolist[CHashedPtr(for_ipo)];
+
+ return listp?*listp:NULL;
+}
+
+
+
+void KX_BlenderSceneConverter::RegisterGameActuator(
+ SCA_IActuator *act,
+ struct bActuator *for_actuator)
+{
+ m_map_blender_to_gameactuator.insert(CHashedPtr(for_actuator), act);
+}
+
+
+
+SCA_IActuator *KX_BlenderSceneConverter::FindGameActuator(
+ struct bActuator *for_actuator)
+{
+ SCA_IActuator **actp = m_map_blender_to_gameactuator[CHashedPtr(for_actuator)];
+
+ return actp?*actp:NULL;
+}
+
+
+
+void KX_BlenderSceneConverter::RegisterGameController(
+ SCA_IController *cont,
+ struct bController *for_controller)
+{
+ m_map_blender_to_gamecontroller.insert(CHashedPtr(for_controller), cont);
+}
+
+
+
+SCA_IController *KX_BlenderSceneConverter::FindGameController(
+ struct bController *for_controller)
+{
+ SCA_IController **contp = m_map_blender_to_gamecontroller[CHashedPtr(for_controller)];
+
+ return contp?*contp:NULL;
+}
+
+
+
+void KX_BlenderSceneConverter::RegisterWorldInfo(
+ KX_WorldInfo *worldinfo)
+{
+ m_worldinfos.push_back(worldinfo);
+}
+
+/*
+ * 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 KX_BlenderSceneConverter::localDel_ipoCurve ( IpoCurve * icu ,struct SpaceIpo* sipo)
+{
+ if (!sipo)
+ return;
+
+ int i;
+ EditIpo *ei= (EditIpo *)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= 0;
+ return;
+ }
+ }
+}
+
+//quick hack
+extern "C"
+{
+ Ipo *add_ipo( char *name, int idcode );
+ char *getIpoCurveName( IpoCurve * icu );
+ struct IpoCurve *verify_ipocurve(struct ID *, short, char *, char *, int);
+ void testhandles_ipocurve(struct IpoCurve *icu);
+ void Mat3ToEul(float tmat[][3], float *eul);
+
+}
+
+IpoCurve* findIpoCurve(IpoCurve* first,char* searchName)
+{
+ IpoCurve* icu1;
+ for( icu1 = first; icu1; icu1 = icu1->next )
+ {
+ char* curveName = getIpoCurveName( icu1 );
+ if( !strcmp( curveName, searchName) )
+ {
+ return icu1;
+ }
+ }
+ return 0;
+}
+
+// this is not longer necesary //rcruiz
+/*Ipo* KX_BlenderSceneConverter::findIpoForName(char* objName)
+{
+ Ipo* ipo_iter = (Ipo*)m_maggie->ipo.first;
+
+ while( ipo_iter )
+ {
+ if( strcmp( objName, ipo_iter->id.name + 2 ) == 0 )
+ {
+ return ipo_iter;
+ }
+ ipo_iter = (Ipo*)ipo_iter->id.next;
+ }
+ return 0;
+}
+*/
+
+void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo)
+{
+
+ KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes();
+ int numScenes = scenes->size();
+ int i;
+ for (i=0;i<numScenes;i++)
+ {
+ KX_Scene* scene = scenes->at(i);
+ //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
+ CListValue* parentList = scene->GetRootParentList();
+ int numObjects = parentList->GetCount();
+ int g;
+ for (g=0;g<numObjects;g++)
+ {
+ KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g);
+ if (gameObj->IsDynamic())
+ {
+ //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController();
+
+ Object* blenderObject = FindBlenderObject(gameObj);
+ if (blenderObject)
+ {
+ //erase existing ipo's
+ Ipo* ipo = blenderObject->ipo;//findIpoForName(blenderObject->id.name+2);
+ if (ipo)
+ { //clear the curve data
+ if (clearIpo){//rcruiz
+ IpoCurve *icu1;
+
+ int numCurves = 0;
+ for( icu1 = (IpoCurve*)ipo->curve.first; icu1; ) {
+
+ IpoCurve* tmpicu = icu1;
+
+ /*int i;
+ BezTriple *bezt;
+ for( bezt = tmpicu->bezt, i = 0; i < tmpicu->totvert; i++, bezt++){
+ printf("(%f,%f,%f),(%f,%f,%f),(%f,%f,%f)\n",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]);
+ }*/
+
+ icu1 = icu1->next;
+ numCurves++;
+
+ BLI_remlink( &( blenderObject->ipo->curve ), tmpicu );
+ if( tmpicu->bezt )
+ MEM_freeN( tmpicu->bezt );
+ MEM_freeN( tmpicu );
+ localDel_ipoCurve( tmpicu ,m_sipo);
+ }
+ }
+ } else
+ { ipo = add_ipo(blenderObject->id.name+2, ID_OB);
+ blenderObject->ipo = ipo;
+
+ }
+
+
+
+
+
+ }
+ }
+
+ }
+
+
+ }
+
+
+
+}
+
+void KX_BlenderSceneConverter::resetNoneDynamicObjectToIpo(){
+
+ if (addInitFromFrame){
+ KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes();
+ int numScenes = scenes->size();
+ if (numScenes>=0){
+ KX_Scene* scene = scenes->at(0);
+ CListValue* parentList = scene->GetRootParentList();
+ for (int ix=0;ix<parentList->GetCount();ix++){
+ KX_GameObject* gameobj = (KX_GameObject*)parentList->GetValue(ix);
+ if (!gameobj->IsDynamic()){
+ Object* blenderobject = FindBlenderObject(gameobj);
+ if (!blenderobject)
+ continue;
+ if (blenderobject->type==OB_ARMATURE)
+ continue;
+ float eu[3];
+ Mat4ToEul(blenderobject->obmat,eu);
+ MT_Point3 pos = MT_Point3(
+ blenderobject->obmat[3][0],
+ blenderobject->obmat[3][1],
+ blenderobject->obmat[3][2]
+ );
+ MT_Vector3 eulxyz = MT_Vector3(
+ eu[0],
+ eu[1],
+ eu[2]
+ );
+ MT_Vector3 scale = MT_Vector3(
+ blenderobject->size[0],
+ blenderobject->size[1],
+ blenderobject->size[2]
+ );
+ gameobj->NodeSetLocalPosition(pos);
+ gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz));
+ gameobj->NodeSetLocalScale(scale);
+ gameobj->NodeUpdateGS(0,true);
+ }
+ }
+ }
+ }
+}
+
+#define TEST_HANDLES_GAME2IPO 0
+
+ ///this generates ipo curves for position, rotation, allowing to use game physics in animation
+void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber)
+{
+
+ KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes();
+ int numScenes = scenes->size();
+ int i;
+ for (i=0;i<numScenes;i++)
+ {
+ KX_Scene* scene = scenes->at(i);
+ //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
+ CListValue* parentList = scene->GetRootParentList();
+ int numObjects = parentList->GetCount();
+ int g;
+ for (g=0;g<numObjects;g++)
+ {
+ KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g);
+ if (gameObj->IsDynamic())
+ {
+ KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController();
+
+ Object* blenderObject = FindBlenderObject(gameObj);
+ if (blenderObject)
+ {
+
+ const MT_Matrix3x3& orn = gameObj->NodeGetWorldOrientation();
+ float eulerAngles[3];
+ float tmat[3][3];
+ for (int r=0;r<3;r++)
+ {
+ for (int c=0;c<3;c++)
+ {
+ tmat[r][c] = orn[c][r];
+ }
+ }
+ Mat3ToEul(tmat, eulerAngles);
+
+ for(int x = 0; x < 3; x++) {
+ eulerAngles[x] *= (float) (180 / 3.14159265f);
+ }
+
+ eulerAngles[0]/=10.f;
+ eulerAngles[1]/=10.f;
+ eulerAngles[2]/=10.f;
+
+
+
+ const MT_Vector3& scale = gameObj->NodeGetWorldScaling();
+ const MT_Point3& position = gameObj->NodeGetWorldPosition();
+
+ Ipo* ipo = blenderObject->ipo;
+ if (ipo)
+ {
+
+ //create the curves, if not existing
+
+ IpoCurve *icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_X);
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_Y);
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_Z);
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_X);
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_Y);
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_Z);
+
+
+
+ //fill the curves with data
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX");
+ if (icu1)
+ {
+ float curVal = position.x();
+ insert_vert_icu(icu1, frameNumber, curVal, 0);
+#ifdef TEST_HANDLES_GAME2IPO
+ testhandles_ipocurve(icu1);
+#endif
+ }
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY");
+ if (icu1)
+ {
+ float curVal = position.y();
+ insert_vert_icu(icu1, frameNumber, curVal, 0);
+#ifdef TEST_HANDLES_GAME2IPO
+
+ testhandles_ipocurve(icu1);
+#endif
+ }
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ");
+ if (icu1)
+ {
+ float curVal = position.z();
+ insert_vert_icu(icu1, frameNumber, curVal, 0);
+#ifdef TEST_HANDLES_GAME2IPO
+ testhandles_ipocurve(icu1);
+#endif
+ }
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX");
+ if (icu1)
+ {
+ float curVal = eulerAngles[0];
+ insert_vert_icu(icu1, frameNumber, curVal, 0);
+#ifdef TEST_HANDLES_GAME2IPO
+
+ testhandles_ipocurve(icu1);
+#endif
+ }
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY");
+ if (icu1)
+ {
+ float curVal = eulerAngles[1];
+ insert_vert_icu(icu1, frameNumber, curVal, 0);
+#ifdef TEST_HANDLES_GAME2IPO
+
+ testhandles_ipocurve(icu1);
+#endif
+ }
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ");
+ if (icu1)
+ {
+ float curVal = eulerAngles[2];
+ insert_vert_icu(icu1, frameNumber, curVal, 0);
+#ifdef TEST_HANDLES_GAME2IPO
+
+ testhandles_ipocurve(icu1);
+#endif
+
+ }
+
+ }
+ }
+ }
+
+ }
+
+
+ }
+
+
+}
+
+
+void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo()
+{
+
+ KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes();
+ int numScenes = scenes->size();
+ int i;
+ for (i=0;i<numScenes;i++)
+ {
+ KX_Scene* scene = scenes->at(i);
+ //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
+ CListValue* parentList = scene->GetRootParentList();
+ int numObjects = parentList->GetCount();
+ int g;
+ for (g=0;g<numObjects;g++)
+ {
+ KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g);
+ if (gameObj->IsDynamic())
+ {
+ KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController();
+
+ Object* blenderObject = FindBlenderObject(gameObj);
+ if (blenderObject)
+ {
+
+ const MT_Matrix3x3& orn = gameObj->NodeGetWorldOrientation();
+ float eulerAngles[3];
+ float tmat[3][3];
+ for (int r=0;r<3;r++)
+ {
+ for (int c=0;c<3;c++)
+ {
+ tmat[r][c] = orn[c][r];
+ }
+ }
+ Mat3ToEul(tmat, eulerAngles);
+
+ for(int x = 0; x < 3; x++) {
+ eulerAngles[x] *= (float) (180 / 3.14159265f);
+ }
+
+ eulerAngles[0]/=10.f;
+ eulerAngles[1]/=10.f;
+ eulerAngles[2]/=10.f;
+
+
+
+ const MT_Vector3& scale = gameObj->NodeGetWorldScaling();
+ const MT_Point3& position = gameObj->NodeGetWorldPosition();
+
+ Ipo* ipo = blenderObject->ipo;
+ if (ipo)
+ {
+
+ //create the curves, if not existing
+
+ IpoCurve *icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_X);
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_Y);
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_Z);
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_X);
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_Y);
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ");
+ if (!icu1)
+ icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_Z);
+
+
+
+ //fill the curves with data
+
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX");
+ if (icu1)
+ {
+ testhandles_ipocurve(icu1);
+ }
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY");
+ if (icu1)
+ {
+ testhandles_ipocurve(icu1);
+ }
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ");
+ if (icu1)
+ {
+ testhandles_ipocurve(icu1);
+ }
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX");
+ if (icu1)
+ {
+ testhandles_ipocurve(icu1);
+ }
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY");
+ if (icu1)
+ {
+ testhandles_ipocurve(icu1);
+ }
+ icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ");
+ if (icu1)
+ {
+ testhandles_ipocurve(icu1);
+ }
+
+ }
+ }
+ }
+
+ }
+
+
+ }
+
+
+
+}
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h
new file mode 100644
index 00000000000..a897922d51b
--- /dev/null
+++ b/source/gameengine/Converter/KX_BlenderSceneConverter.h
@@ -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 *****
+ */
+#ifndef __KX_BLENDERSCENECONVERTER_H
+#define __KX_BLENDERSCENECONVERTER_H
+
+#include "KX_HashedPtr.h"
+#include "GEN_Map.h"
+
+#include "KX_ISceneConverter.h"
+#include "KX_IpoConvert.h"
+
+class KX_WorldInfo;
+class SCA_IActuator;
+class SCA_IController;
+class RAS_MeshObject;
+class RAS_IPolyMaterial;
+class BL_InterpolatorList;
+class BL_Material;
+struct IpoCurve;
+struct Main;
+struct SpaceIpo;
+
+class KX_BlenderSceneConverter : public KX_ISceneConverter
+{
+ vector<KX_WorldInfo*> m_worldinfos;
+ vector<RAS_IPolyMaterial*> m_polymaterials;
+ vector<RAS_MeshObject*> m_meshobjects;
+ vector<BL_Material *> m_materials;
+
+ GEN_Map<CHashedPtr,struct Object*> m_map_gameobject_to_blender;
+ GEN_Map<CHashedPtr,KX_GameObject*> m_map_blender_to_gameobject;
+
+ GEN_Map<CHashedPtr,RAS_MeshObject*> m_map_mesh_to_gamemesh;
+// GEN_Map<CHashedPtr,DT_ShapeHandle> m_map_gamemesh_to_sumoshape;
+
+ GEN_Map<CHashedPtr,SCA_IActuator*> m_map_blender_to_gameactuator;
+ GEN_Map<CHashedPtr,SCA_IController*> m_map_blender_to_gamecontroller;
+
+ GEN_Map<CHashedPtr,BL_InterpolatorList*> m_map_blender_to_gameipolist;
+
+ Main* m_maggie;
+ SpaceIpo* m_sipo;
+
+ STR_String m_newfilename;
+ class KX_KetsjiEngine* m_ketsjiEngine;
+ bool m_alwaysUseExpandFraming;
+ bool m_usemat;
+
+ void localDel_ipoCurve ( IpoCurve * icu ,struct SpaceIpo* sipo);
+// struct Ipo* findIpoForName(char* objName);
+
+public:
+ KX_BlenderSceneConverter(
+ Main* maggie,
+ SpaceIpo *sipo,
+ class KX_KetsjiEngine* engine
+ );
+
+ virtual ~KX_BlenderSceneConverter();
+
+ /* Scenename: name of the scene to be converted.
+ * destinationscene: pass an empty scene, everything goes into this
+ * dictobj: python dictionary (for pythoncontrollers)
+ */
+ virtual void ConvertScene(
+ const STR_String& scenename,
+ class KX_Scene* destinationscene,
+ PyObject* dictobj,
+ class SCA_IInputDevice* keyinputdev,
+ class RAS_IRenderTools* rendertools,
+ class RAS_ICanvas* canvas
+ );
+
+ void SetNewFileName(const STR_String& filename);
+ bool TryAndLoadNewFile();
+
+ void SetAlwaysUseExpandFraming(bool to_what);
+
+ void RegisterGameObject(KX_GameObject *gameobject, struct Object *for_blenderobject);
+ KX_GameObject *FindGameObject(struct Object *for_blenderobject);
+ struct Object *FindBlenderObject(KX_GameObject *for_gameobject);
+
+ void RegisterGameMesh(RAS_MeshObject *gamemesh, struct Mesh *for_blendermesh);
+ RAS_MeshObject *FindGameMesh(struct Mesh *for_blendermesh, unsigned int onlayer);
+
+// void RegisterSumoShape(DT_ShapeHandle shape, RAS_MeshObject *for_gamemesh);
+// DT_ShapeHandle FindSumoShape(RAS_MeshObject *for_gamemesh);
+
+ void RegisterPolyMaterial(RAS_IPolyMaterial *polymat);
+
+ void RegisterBlenderMaterial(BL_Material *mat);
+
+ void RegisterInterpolatorList(BL_InterpolatorList *ipoList, struct Ipo *for_ipo);
+ BL_InterpolatorList *FindInterpolatorList(struct Ipo *for_ipo);
+
+ void RegisterGameActuator(SCA_IActuator *act, struct bActuator *for_actuator);
+ SCA_IActuator *FindGameActuator(struct bActuator *for_actuator);
+
+ void RegisterGameController(SCA_IController *cont, struct bController *for_controller);
+ SCA_IController *FindGameController(struct bController *for_controller);
+
+ void RegisterWorldInfo(KX_WorldInfo *worldinfo);
+
+ virtual void ResetPhysicsObjectsAnimationIpo(bool clearIpo);
+
+ ///this is for reseting the position,rotation and scale of the gameobjet that is not dynamic
+ virtual void resetNoneDynamicObjectToIpo();
+
+ ///this generates ipo curves for position, rotation, allowing to use game physics in animation
+ virtual void WritePhysicsObjectToAnimationIpo(int frameNumber);
+ virtual void TestHandlesPhysicsObjectToAnimationIpo();
+
+ // use blender materials
+ virtual void SetMaterials(bool val);
+ virtual bool GetMaterials();
+
+};
+
+#endif //__KX_BLENDERSCENECONVERTER_H
+
diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp
new file mode 100644
index 00000000000..a6baa04b045
--- /dev/null
+++ b/source/gameengine/Converter/KX_ConvertActuators.cpp
@@ -0,0 +1,862 @@
+/**
+* $Id$
+*
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+* Convert Blender actuators for use in the GameEngine
+*/
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif //WIN32
+
+#define BLENDER_HACK_DTIME 0.02
+
+#include "KX_BlenderSceneConverter.h"
+#include "KX_ConvertActuators.h"
+
+// Actuators
+//SCA logiclibrary native logicbricks
+#include "SCA_PropertyActuator.h"
+#include "SCA_LogicManager.h"
+#include "SCA_RandomActuator.h"
+
+
+// Ketsji specific logicbricks
+#include "KX_SceneActuator.h"
+#include "KX_IpoActuator.h"
+#include "KX_SoundActuator.h"
+#include "KX_CDActuator.h"
+#include "KX_ObjectActuator.h"
+#include "KX_TrackToActuator.h"
+#include "KX_ConstraintActuator.h"
+#include "KX_CameraActuator.h"
+#include "KX_GameActuator.h"
+#include "KX_VisibilityActuator.h"
+#include "KX_SCA_AddObjectActuator.h"
+#include "KX_SCA_EndObjectActuator.h"
+#include "KX_SCA_ReplaceMeshActuator.h"
+
+#include "KX_Scene.h"
+#include "KX_KetsjiEngine.h"
+
+#include "IntValue.h"
+#include "KX_GameObject.h"
+
+/* This little block needed for linking to Blender... */
+
+#include "BLI_blenlib.h"
+
+#include "KX_NetworkMessageActuator.h"
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include "DNA_object_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_actuator_types.h"
+#include "DNA_packedFile_types.h"
+#include "BL_ActionActuator.h"
+/* end of blender include block */
+
+#include "BL_BlenderDataConversion.h"
+
+/**
+KX_BLENDERTRUNC needed to round 'almost' zero values to zero, else velocities etc. are incorrectly set
+*/
+
+#define KX_BLENDERTRUNC(x) (( x < 0.0001 && x > -0.0001 ) ? 0.0 : x)
+
+void BL_ConvertActuators(char* maggiename,
+ struct Object* blenderobject,
+ KX_GameObject* gameobj,
+ SCA_LogicManager* logicmgr,
+ KX_Scene* scene,
+ KX_KetsjiEngine* ketsjiEngine,
+ int & executePriority,
+ int activeLayerBitInfo,
+ bool isInActiveLayer,
+ RAS_IRenderTools* rendertools,
+ KX_BlenderSceneConverter* converter
+ )
+{
+
+ int uniqueint = 0;
+ bActuator* bact = (bActuator*) blenderobject->actuators.first;
+ while(bact)
+ {
+ STR_String uniquename = bact->name;
+ STR_String objectname = gameobj->GetName();
+
+ SCA_IActuator* baseact = NULL;
+ switch (bact->type)
+ {
+ case ACT_OBJECT:
+ {
+ bObjectActuator* obact = (bObjectActuator*) bact->data;
+ MT_Vector3 forcevec(KX_BLENDERTRUNC(obact->forceloc[0]),
+ KX_BLENDERTRUNC(obact->forceloc[1]),
+ KX_BLENDERTRUNC(obact->forceloc[2]));
+ MT_Vector3 torquevec(obact->forcerot[0],obact->forcerot[1],obact->forcerot[2]);
+ MT_Vector3 dlocvec ( KX_BLENDERTRUNC(obact->dloc[0]),
+ KX_BLENDERTRUNC(obact->dloc[1]),
+ KX_BLENDERTRUNC(obact->dloc[2]));
+ MT_Vector3 drotvec ( KX_BLENDERTRUNC(obact->drot[0]),obact->drot[1],obact->drot[2]);
+ MT_Vector3 linvelvec ( KX_BLENDERTRUNC(obact->linearvelocity[0]),
+ KX_BLENDERTRUNC(obact->linearvelocity[1]),
+ KX_BLENDERTRUNC(obact->linearvelocity[2]));
+ MT_Vector3 angvelvec ( KX_BLENDERTRUNC(obact->angularvelocity[0]),
+ KX_BLENDERTRUNC(obact->angularvelocity[1]),
+ KX_BLENDERTRUNC(obact->angularvelocity[2]));
+
+ drotvec /= BLENDER_HACK_DTIME;
+ //drotvec /= BLENDER_HACK_DTIME;
+ drotvec *= MT_2_PI/360.0;
+ //dlocvec /= BLENDER_HACK_DTIME;
+ //linvelvec /= BLENDER_HACK_DTIME;
+ //angvelvec /= BLENDER_HACK_DTIME;
+
+ /* Blender uses a bit vector internally for the local-flags. In */
+ /* KX, we have four bools. The compiler should be smart enough */
+ /* to do the right thing. We need to explicitly convert here! */
+
+ KX_LocalFlags bitLocalFlag;
+
+ bitLocalFlag.Force = bool((obact->flag & ACT_FORCE_LOCAL)!=0);
+ bitLocalFlag.Torque = bool((obact->flag & ACT_TORQUE_LOCAL) !=0);//rlocal;
+ bitLocalFlag.DLoc = bool((obact->flag & ACT_DLOC_LOCAL)!=0);
+ bitLocalFlag.DRot = bool((obact->flag & ACT_DROT_LOCAL)!=0);
+ bitLocalFlag.LinearVelocity = bool((obact->flag & ACT_LIN_VEL_LOCAL)!=0);
+ bitLocalFlag.AngularVelocity = bool((obact->flag & ACT_ANG_VEL_LOCAL)!=0);
+
+ bitLocalFlag.AddOrSetLinV = bool((obact->flag & ACT_ADD_LIN_VEL)!=0);
+
+
+ KX_ObjectActuator* tmpbaseact = new KX_ObjectActuator(gameobj,
+ forcevec.getValue(),
+ torquevec.getValue(),
+ dlocvec.getValue(),
+ drotvec.getValue(),
+ linvelvec.getValue(),
+ angvelvec.getValue(),
+ bitLocalFlag
+ );
+ baseact = tmpbaseact;
+ break;
+ }
+ case ACT_ACTION:
+ {
+ if (blenderobject->type==OB_ARMATURE){
+ bActionActuator* actact = (bActionActuator*) bact->data;
+ STR_String propname = (actact->name ? actact->name : "");
+
+ BL_ActionActuator* tmpbaseact = new BL_ActionActuator(
+ gameobj,
+ propname,
+ actact->sta,
+ actact->end,
+ actact->act,
+ actact->type, // + 1, because Blender starts to count at zero,
+ actact->blendin,
+ actact->priority,
+ actact->stridelength
+ // Ketsji at 1, because zero is reserved for "NoDef"
+ );
+ baseact= tmpbaseact;
+ break;
+ }
+ else
+ printf ("Discarded action actuator from non-armature object [%s]\n", blenderobject->id.name+2);
+ }
+ case ACT_IPO:
+ {
+ bIpoActuator* ipoact = (bIpoActuator*) bact->data;
+ bool ipochild = (ipoact->flag & ACT_IPOCHILD) !=0;
+ STR_String propname = ( ipoact->name ? ipoact->name : "");
+ // first bit?
+ bool ipo_as_force = (ipoact->flag & ACT_IPOFORCE);
+ bool force_local = (ipoact->flag & ACT_IPOFORCE_LOCAL);
+
+ KX_IpoActuator* tmpbaseact = new KX_IpoActuator(
+ gameobj,
+ propname ,
+ ipoact->sta,
+ ipoact->end,
+ ipochild,
+ ipoact->type + 1, // + 1, because Blender starts to count at zero,
+ // Ketsji at 1, because zero is reserved for "NoDef"
+ ipo_as_force,
+ force_local
+ );
+ baseact = tmpbaseact;
+ break;
+ }
+ case ACT_LAMP:
+ {
+ break;
+ }
+ case ACT_CAMERA:
+ {
+ bCameraActuator *camact = (bCameraActuator *) bact->data;
+ if (camact->ob) {
+ KX_GameObject *tmpgob = converter->FindGameObject(camact->ob);
+
+ /* visifac, fac and axis are not copied from the struct... */
+ /* that's some internal state... */
+ KX_CameraActuator *tmpcamact
+ = new KX_CameraActuator(gameobj,
+ tmpgob,
+ camact->height,
+ camact->min,
+ camact->max,
+ camact->axis=='x');
+ baseact = tmpcamact;
+ }
+ break;
+ }
+ case ACT_MESSAGE:
+ {
+ bMessageActuator *msgAct = (bMessageActuator *) bact->data;
+
+ /**
+ * Get the name of the properties that objects must own that
+ * we're sending to, if present
+ */
+ STR_String toPropName = (msgAct->toPropName
+ ? (char*) msgAct->toPropName
+ : "");
+ /**
+ * Get the Message Subject to send.
+ */
+ STR_String subject = (msgAct->subject
+ ? (char*) msgAct->subject
+ : "");
+
+ /**
+ * Get the bodyType
+ */
+ int bodyType = msgAct->bodyType;
+
+ /**
+ * Get the body (text message or property name whose value
+ * we'll be sending, might be empty
+ */
+ STR_String body = (msgAct->body
+ ? (char*) msgAct->body
+ : "");
+
+ KX_NetworkMessageActuator *tmpmsgact =
+ new KX_NetworkMessageActuator(
+ gameobj, // actuator controlling object
+ scene->GetNetworkScene(), // needed for replication
+ toPropName,
+ subject,
+ bodyType,
+ body);
+ baseact = tmpmsgact;
+ break;
+ }
+ case ACT_MATERIAL:
+ {
+ break;
+ }
+ case ACT_SOUND:
+ {
+ bSoundActuator* soundact = (bSoundActuator*) bact->data;
+ /* get type, and possibly a start and end frame */
+ short startFrame = soundact->sta, stopFrame = soundact->end;
+ KX_SoundActuator::KX_SOUNDACT_TYPE
+ soundActuatorType = KX_SoundActuator::KX_SOUNDACT_NODEF;
+
+ switch(soundact->type) {
+ case ACT_SND_PLAY_STOP_SOUND:
+ soundActuatorType = KX_SoundActuator::KX_SOUNDACT_PLAYSTOP;
+ break;
+ case ACT_SND_PLAY_END_SOUND:
+ soundActuatorType = KX_SoundActuator::KX_SOUNDACT_PLAYEND;
+ break;
+ case ACT_SND_LOOP_STOP_SOUND:
+ soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPSTOP;
+ break;
+ case ACT_SND_LOOP_END_SOUND:
+ soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPEND;
+ break;
+ case ACT_SND_LOOP_BIDIRECTIONAL_SOUND:
+ soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPBIDIRECTIONAL;
+ break;
+ case ACT_SND_LOOP_BIDIRECTIONAL_STOP_SOUND:
+ soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP;
+ break;
+
+ default:
+ /* This is an error!!! */
+ soundActuatorType = KX_SoundActuator::KX_SOUNDACT_NODEF;
+ }
+
+ if (soundActuatorType != KX_SoundActuator::KX_SOUNDACT_NODEF)
+ {
+ SND_SoundObject* sndobj = NULL;
+
+ if (soundact->sound)
+ {
+ SND_Scene* soundscene = scene->GetSoundScene();
+ STR_String samplename = soundact->sound->name;
+
+ bool sampleisloaded = false;
+
+ /* let's see if the sample was already loaded */
+ if (soundscene->IsSampleLoaded(samplename))
+ {
+ sampleisloaded = true;
+ }
+ else
+ {
+ /* if not, make it so */
+ PackedFile* pf = soundact->sound->newpackedfile;
+
+ /* but we need a packed file then */
+ if (pf)
+ {
+ if (soundscene->LoadSample(samplename, pf->data, pf->size) > -1)
+ sampleisloaded = true;
+ }
+ /* or else load it from disk */
+ else
+ {
+ /* but we need to convert the samplename into absolute pathname first */
+ BLI_convertstringcode(soundact->sound->name, maggiename, 0);
+ samplename = soundact->sound->name;
+
+ /* and now we can load it */
+ if (soundscene->LoadSample(samplename, NULL, 0) > -1)
+ sampleisloaded = true;
+ }
+ }
+
+ if (sampleisloaded)
+ {
+ sndobj = new SND_SoundObject();
+ sndobj->SetSampleName(samplename.Ptr());
+ sndobj->SetObjectName(bact->name);
+ sndobj->SetRollOffFactor(soundact->sound->attenuation);
+ sndobj->SetGain(soundact->sound->volume);
+ sndobj->SetPitch(exp((soundact->sound->pitch / 12.0) * log(2.0)));
+ // sndobj->SetLoopStart(soundact->sound->loopstart);
+ // sndobj->SetLoopStart(soundact->sound->loopend);
+ if (soundact->sound->flags & SOUND_FLAGS_LOOP)
+ {
+ if (soundact->sound->flags & SOUND_FLAGS_BIDIRECTIONAL_LOOP)
+ sndobj->SetLoopMode(SND_LOOP_BIDIRECTIONAL);
+ else
+ sndobj->SetLoopMode(SND_LOOP_NORMAL);
+ }
+ else
+ sndobj->SetLoopMode(SND_LOOP_OFF);
+
+ if (soundact->sound->flags & SOUND_FLAGS_PRIORITY)
+ sndobj->SetHighPriority(true);
+ else
+ sndobj->SetHighPriority(false);
+
+ if (soundact->sound->flags & SOUND_FLAGS_3D)
+ sndobj->Set3D(true);
+ else
+ sndobj->Set3D(false);
+
+ KX_SoundActuator* tmpsoundact =
+ new KX_SoundActuator(gameobj,
+ sndobj,
+ scene->GetSoundScene(), // needed for replication!
+ soundActuatorType,
+ startFrame,
+ stopFrame);
+
+ tmpsoundact->SetName(bact->name);
+ baseact = tmpsoundact;
+ soundscene->AddObject(sndobj);
+ } else {
+ std::cout << "WARNING: Sound actuator " << bact->name << " failed to load sample." << std::endl;
+ }
+ }
+ }
+ break;
+ }
+ case ACT_CD:
+ {
+ bCDActuator* cdact = (bCDActuator*) bact->data;
+ /* get type, and possibly a start and end frame */
+ short startFrame = cdact->sta, stopFrame = cdact->end;
+ KX_CDActuator::KX_CDACT_TYPE
+ cdActuatorType = KX_CDActuator::KX_CDACT_NODEF;
+
+ switch(cdact->type)
+ {
+ case ACT_CD_PLAY_ALL:
+ cdActuatorType = KX_CDActuator::KX_CDACT_PLAY_ALL;
+ break;
+ case ACT_CD_PLAY_TRACK:
+ cdActuatorType = KX_CDActuator::KX_CDACT_PLAY_TRACK;
+ break;
+ case ACT_CD_LOOP_TRACK:
+ cdActuatorType = KX_CDActuator::KX_CDACT_LOOP_TRACK;
+ break;
+ case ACT_CD_VOLUME:
+ cdActuatorType = KX_CDActuator::KX_CDACT_VOLUME;
+ break;
+ case ACT_CD_STOP:
+ cdActuatorType = KX_CDActuator::KX_CDACT_STOP;
+ break;
+ case ACT_CD_PAUSE:
+ cdActuatorType = KX_CDActuator::KX_CDACT_PAUSE;
+ break;
+ case ACT_CD_RESUME:
+ cdActuatorType = KX_CDActuator::KX_CDACT_RESUME;
+ break;
+
+ default:
+ /* This is an error!!! */
+ cdActuatorType = KX_CDActuator::KX_CDACT_NODEF;
+ }
+
+ if (cdActuatorType != KX_CDActuator::KX_CDACT_NODEF)
+ {
+ SND_CDObject* pCD = SND_CDObject::Instance();
+
+ if (pCD)
+ {
+ pCD->SetGain(cdact->volume);
+
+ KX_CDActuator* tmpcdact =
+ new KX_CDActuator(gameobj,
+ scene->GetSoundScene(), // needed for replication!
+ cdActuatorType,
+ cdact->track,
+ startFrame,
+ stopFrame);
+
+ tmpcdact->SetName(bact->name);
+ baseact = tmpcdact;
+ }
+ }
+ break;
+ }
+ case ACT_PROPERTY:
+ {
+ bPropertyActuator* propact = (bPropertyActuator*) bact->data;
+ CValue* destinationObj = NULL;
+
+ /*
+ here the destinationobject is searched. problem with multiple scenes: other scenes
+ have not been converted yet, so the destobj will not be found, so the prop will
+ not be copied.
+ possible solutions:
+ - convert everything when possible and not realtime only when needed.
+ - let the object-with-property report itself to the act when converted
+ */
+ if (propact->ob)
+ destinationObj = converter->FindGameObject(propact->ob);
+
+ SCA_PropertyActuator* tmppropact = new SCA_PropertyActuator(
+ gameobj,
+ destinationObj,
+ propact->name,
+ propact->value,
+ propact->type+1); // + 1 because Ketsji Logic starts
+ // with 0 for KX_ACT_PROP_NODEF
+ baseact = tmppropact;
+ break;
+ }
+ case ACT_EDIT_OBJECT:
+ {
+ bEditObjectActuator *editobact
+ = (bEditObjectActuator *) bact->data;
+ /* There are four different kinds of 'edit object' thingies */
+ /* The alternative to this lengthy conversion is packing */
+ /* several actuators in one, which is not very nice design.. */
+ switch (editobact->type) {
+ case ACT_EDOB_ADD_OBJECT:
+ {
+
+ // does the 'original' for replication exists, and
+ // is it in a non-active layer ?
+ CValue* originalval = NULL;
+ if (editobact->ob && !(editobact->ob->lay & activeLayerBitInfo))
+ originalval = converter->FindGameObject(editobact->ob);
+
+ MT_Vector3 linvelvec ( KX_BLENDERTRUNC(editobact->linVelocity[0]),
+ KX_BLENDERTRUNC(editobact->linVelocity[1]),
+ KX_BLENDERTRUNC(editobact->linVelocity[2]));
+
+ KX_SCA_AddObjectActuator* tmpaddact =
+ new KX_SCA_AddObjectActuator(
+ gameobj,
+ originalval,
+ editobact->time,
+ scene,
+ linvelvec.getValue(),
+ editobact->localflag!=0
+ );
+
+ //editobact->ob to gameobj
+ baseact = tmpaddact;
+ }
+ break;
+ case ACT_EDOB_END_OBJECT:
+ {
+ KX_SCA_EndObjectActuator* tmpendact
+ = new KX_SCA_EndObjectActuator(gameobj,scene);
+ baseact = tmpendact;
+ }
+ break;
+ case ACT_EDOB_REPLACE_MESH:
+ {
+ RAS_MeshObject *tmpmesh = NULL;
+ if (editobact->me)
+ tmpmesh = BL_ConvertMesh(
+ editobact->me,
+ blenderobject,
+ rendertools,
+ scene,
+ converter
+ );
+
+ KX_SCA_ReplaceMeshActuator* tmpreplaceact
+ = new KX_SCA_ReplaceMeshActuator(
+ gameobj,
+ tmpmesh,
+ scene
+ );
+
+ baseact = tmpreplaceact;
+ }
+ break;
+ case ACT_EDOB_TRACK_TO:
+ {
+ SCA_IObject* originalval = NULL;
+ if (editobact->ob)
+ originalval = converter->FindGameObject(editobact->ob);
+
+ KX_TrackToActuator* tmptrackact
+ = new KX_TrackToActuator(gameobj,
+ originalval,
+ editobact->time,
+ editobact->flag,
+ blenderobject->trackflag,
+ blenderobject->upflag
+ );
+ baseact = tmptrackact;
+ }
+ }
+ break;
+ }
+ case ACT_CONSTRAINT:
+ {
+ float min = 0.0, max = 0.0;
+ KX_ConstraintActuator::KX_CONSTRAINTTYPE locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_NODEF;
+ bConstraintActuator *conact
+ = (bConstraintActuator*) bact->data;
+ /* convert settings... degrees in the ui become radians */
+ /* internally */
+ switch (conact->flag) {
+ case ACT_CONST_LOCX:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCX;
+ min = conact->minloc[0];
+ max = conact->maxloc[0];
+ break;
+ case ACT_CONST_LOCY:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCY;
+ min = conact->minloc[1];
+ max = conact->maxloc[1];
+ break;
+ case ACT_CONST_LOCZ:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCZ;
+ min = conact->minloc[2];
+ max = conact->maxloc[2];
+ break;
+ case ACT_CONST_ROTX:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTX;
+ min = MT_2_PI * conact->minrot[0] / 360.0;
+ max = MT_2_PI * conact->maxrot[0] / 360.0;
+ break;
+ case ACT_CONST_ROTY:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTY;
+ min = MT_2_PI * conact->minrot[1] / 360.0;
+ max = MT_2_PI * conact->maxrot[1] / 360.0;
+ break;
+ case ACT_CONST_ROTZ:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTZ;
+ min = MT_2_PI * conact->minrot[2] / 360.0;
+ max = MT_2_PI * conact->maxrot[2] / 360.0;
+ break;
+ default:
+ ; /* error */
+ }
+ KX_ConstraintActuator *tmpconact
+ = new KX_ConstraintActuator(gameobj,
+ conact->damp,
+ min,
+ max,
+ locrot);
+ baseact = tmpconact;
+ break;
+ }
+ case ACT_GROUP:
+ {
+ // deprecated
+ }
+ break;
+ case ACT_SCENE:
+ {
+ bSceneActuator *sceneact = (bSceneActuator *) bact->data;
+ STR_String nextSceneName("");
+
+ KX_SceneActuator* tmpsceneact;
+ int mode = KX_SceneActuator::KX_SCENE_NODEF;
+ KX_Camera *cam = NULL;
+ //KX_Scene* scene = NULL;
+ switch (sceneact->type)
+ {
+ case ACT_SCENE_RESUME:
+ case ACT_SCENE_SUSPEND:
+ case ACT_SCENE_ADD_FRONT:
+ case ACT_SCENE_ADD_BACK:
+ case ACT_SCENE_REMOVE:
+ case ACT_SCENE_SET:
+ {
+ switch (sceneact->type)
+ {
+ case ACT_SCENE_RESUME:
+ mode = KX_SceneActuator::KX_SCENE_RESUME;
+ break;
+ case ACT_SCENE_SUSPEND:
+ mode = KX_SceneActuator::KX_SCENE_SUSPEND;
+ break;
+ case ACT_SCENE_ADD_FRONT:
+ mode = KX_SceneActuator::KX_SCENE_ADD_FRONT_SCENE;
+ break;
+ case ACT_SCENE_ADD_BACK:
+ mode = KX_SceneActuator::KX_SCENE_ADD_BACK_SCENE;
+ break;
+ case ACT_SCENE_REMOVE:
+ mode = KX_SceneActuator::KX_SCENE_REMOVE_SCENE;
+ break;
+ case ACT_SCENE_SET:
+ default:
+ mode = KX_SceneActuator::KX_SCENE_SET_SCENE;
+ break;
+ };
+
+ if (sceneact->scene)
+ {
+ nextSceneName = sceneact->scene->id.name + 2; // this '2' is necessary to remove prefix 'SC'
+ }
+
+ break;
+ }
+ case ACT_SCENE_CAMERA:
+ if (sceneact->camera)
+ {
+ mode = KX_SceneActuator::KX_SCENE_SET_CAMERA;
+ cam = (KX_Camera*) converter->FindGameObject(sceneact->camera);
+ }
+ else
+ {
+ // TODO:warn user
+ }
+ break;
+ case ACT_SCENE_RESTART:
+ {
+
+ mode = KX_SceneActuator::KX_SCENE_RESTART;
+ break;
+ }
+ default:
+ ; /* flag error */
+ }
+ tmpsceneact = new KX_SceneActuator(gameobj,
+ mode,
+ scene,
+ ketsjiEngine,
+ nextSceneName,
+ cam);
+ baseact = tmpsceneact;
+ break;
+ }
+ case ACT_GAME:
+ {
+ bGameActuator *gameact = (bGameActuator *) bact->data;
+ KX_GameActuator* tmpgameact;
+ STR_String filename = maggiename;
+ STR_String loadinganimationname = "";
+ int mode = KX_GameActuator::KX_GAME_NODEF;
+ switch (gameact->type)
+ {
+ case ACT_GAME_LOAD:
+ {
+ mode = KX_GameActuator::KX_GAME_LOAD;
+ filename = gameact->filename;
+ loadinganimationname = gameact->loadaniname;
+ break;
+ }
+ case ACT_GAME_START:
+ {
+ mode = KX_GameActuator::KX_GAME_START;
+ filename = gameact->filename;
+ loadinganimationname = gameact->loadaniname;
+ break;
+ }
+ case ACT_GAME_RESTART:
+ {
+ mode = KX_GameActuator::KX_GAME_RESTART;
+ break;
+ }
+ case ACT_GAME_QUIT:
+ {
+ mode = KX_GameActuator::KX_GAME_QUIT;
+ break;
+ }
+ default:
+ ; /* flag error */
+ }
+ tmpgameact = new KX_GameActuator(gameobj,
+ mode,
+ filename,
+ loadinganimationname,
+ scene,
+ ketsjiEngine);
+ baseact = tmpgameact;
+
+ break;
+ }
+ case ACT_RANDOM:
+ {
+ bRandomActuator *randAct
+ = (bRandomActuator *) bact->data;
+
+ unsigned long seedArg = randAct->seed;
+ SCA_RandomActuator::KX_RANDOMACT_MODE modeArg
+ = SCA_RandomActuator::KX_RANDOMACT_NODEF;
+ SCA_RandomActuator *tmprandomact;
+ float paraArg1 = 0.0;
+ float paraArg2 = 0.0;
+
+ switch (randAct->distribution) {
+ case ACT_RANDOM_BOOL_CONST:
+ modeArg = SCA_RandomActuator::KX_RANDOMACT_BOOL_CONST;
+ paraArg1 = (float) randAct->int_arg_1;
+ break;
+ case ACT_RANDOM_BOOL_UNIFORM:
+ modeArg = SCA_RandomActuator::KX_RANDOMACT_BOOL_UNIFORM;
+ break;
+ case ACT_RANDOM_BOOL_BERNOUILLI:
+ paraArg1 = randAct->float_arg_1;
+ modeArg = SCA_RandomActuator::KX_RANDOMACT_BOOL_BERNOUILLI;
+ break;
+ case ACT_RANDOM_INT_CONST:
+ modeArg = SCA_RandomActuator::KX_RANDOMACT_INT_CONST;
+ paraArg1 = (float) randAct->int_arg_1;
+ break;
+ case ACT_RANDOM_INT_UNIFORM:
+ paraArg1 = (float) randAct->int_arg_1;
+ paraArg2 = (float) randAct->int_arg_2;
+ modeArg = SCA_RandomActuator::KX_RANDOMACT_INT_UNIFORM;
+ break;
+ case ACT_RANDOM_INT_POISSON:
+ paraArg1 = randAct->float_arg_1;
+ modeArg = SCA_RandomActuator::KX_RANDOMACT_INT_POISSON;
+ break;
+ case ACT_RANDOM_FLOAT_CONST:
+ paraArg1 = randAct->float_arg_1;
+ modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_CONST;
+ break;
+ case ACT_RANDOM_FLOAT_UNIFORM:
+ paraArg1 = randAct->float_arg_1;
+ paraArg2 = randAct->float_arg_2;
+ modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_UNIFORM;
+ break;
+ case ACT_RANDOM_FLOAT_NORMAL:
+ paraArg1 = randAct->float_arg_1;
+ paraArg2 = randAct->float_arg_2;
+ modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_NORMAL;
+ break;
+ case ACT_RANDOM_FLOAT_NEGATIVE_EXPONENTIAL:
+ paraArg1 = randAct->float_arg_1;
+ modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL;
+ break;
+ default:
+ ; /* error */
+ }
+ tmprandomact = new SCA_RandomActuator(gameobj,
+ seedArg,
+ modeArg,
+ paraArg1,
+ paraArg2,
+ randAct->propname);
+ baseact = tmprandomact;
+ }
+ break;
+
+ case ACT_VISIBILITY:
+ {
+ bVisibilityActuator *vis_act = (bVisibilityActuator *) bact->data;
+ KX_VisibilityActuator * tmp_vis_act = NULL;
+ bool v = ((vis_act->flag & ACT_VISIBILITY_INVISIBLE) != 0);
+
+ tmp_vis_act =
+ new KX_VisibilityActuator(gameobj,
+ !v);
+
+ baseact = tmp_vis_act;
+ }
+ break;
+
+ default:
+ ; /* generate some error */
+ }
+
+ if (baseact)
+ {
+ baseact->SetExecutePriority(executePriority++);
+ uniquename += "#ACT#";
+ uniqueint++;
+ CIntValue* uniqueval = new CIntValue(uniqueint);
+ uniquename += uniqueval->GetText();
+ uniqueval->Release();
+ baseact->SetName(STR_String(bact->name));
+ //gameobj->SetProperty(uniquename,baseact);
+ gameobj->AddActuator(baseact);
+
+ converter->RegisterGameActuator(baseact, bact);
+ }
+
+ bact = bact->next;
+ }
+}
+
diff --git a/source/gameengine/Converter/KX_ConvertActuators.h b/source/gameengine/Converter/KX_ConvertActuators.h
new file mode 100644
index 00000000000..1e6e96e2e7c
--- /dev/null
+++ b/source/gameengine/Converter/KX_ConvertActuators.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 __KX_CONVERTACTUATORS_H
+#define __KX_CONVERTACTUATORS_H
+
+void BL_ConvertActuators(char* maggiename,
+ struct Object* blenderobject,
+ class KX_GameObject* gameobj,
+ class SCA_LogicManager* logicmgr,
+ class KX_Scene* scene,
+ class KX_KetsjiEngine* ketsjiEngine,
+ int & executePriority,
+ int activeLayerBitInfo,
+ bool isInActiveLayer,
+ class RAS_IRenderTools* rendertools,
+ class KX_BlenderSceneConverter* converter);
+
+
+#endif //__KX_CONVERTACTUATORS_H
+
diff --git a/source/gameengine/Converter/KX_ConvertControllers.cpp b/source/gameengine/Converter/KX_ConvertControllers.cpp
new file mode 100644
index 00000000000..5b30f5a4a2e
--- /dev/null
+++ b/source/gameengine/Converter/KX_ConvertControllers.cpp
@@ -0,0 +1,182 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "MEM_guardedalloc.h"
+
+#include "KX_BlenderSceneConverter.h"
+#include "KX_ConvertControllers.h"
+#include "KX_Python.h"
+
+// Controller
+#include "SCA_ANDController.h"
+#include "SCA_ORController.h"
+#include "SCA_PythonController.h"
+#include "SCA_ExpressionController.h"
+
+#include "SCA_LogicManager.h"
+#include "KX_GameObject.h"
+#include "IntValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* This little block needed for linking to Blender... */
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include "DNA_object_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_text_types.h"
+
+#include "BKE_text.h"
+
+#include "BLI_blenlib.h"
+
+/* end of blender include block */
+
+
+ static void
+LinkControllerToActuators(
+ SCA_IController *game_controller,
+ bController* bcontr,
+ SCA_LogicManager* logicmgr,
+ KX_BlenderSceneConverter* converter
+) {
+ // Iterate through the actuators of the game blender
+ // controller and find the corresponding ketsji actuator.
+
+ for (int i=0;i<bcontr->totlinks;i++)
+ {
+ bActuator* bact = (bActuator*) bcontr->links[i];
+ SCA_IActuator *game_actuator = converter->FindGameActuator(bact);
+ if (game_actuator) {
+ logicmgr->RegisterToActuator(game_controller, game_actuator);
+ }
+ }
+}
+
+
+void BL_ConvertControllers(
+ struct Object* blenderobject,
+ class KX_GameObject* gameobj,
+ SCA_LogicManager* logicmgr,
+ PyObject* pythondictionary,
+ int &executePriority,
+ int activeLayerBitInfo,
+ bool isInActiveLayer,
+ KX_BlenderSceneConverter* converter
+) {
+ int uniqueint=0;
+ bController* bcontr = (bController*)blenderobject->controllers.first;
+ while (bcontr)
+ {
+ SCA_IController* gamecontroller = NULL;
+ switch(bcontr->type)
+ {
+ case CONT_LOGIC_AND:
+ {
+ gamecontroller = new SCA_ANDController(gameobj);
+ LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter);
+ break;
+ }
+ case CONT_LOGIC_OR:
+ {
+ gamecontroller = new SCA_ORController(gameobj);
+ LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter);
+ break;
+ }
+ case CONT_EXPRESSION:
+ {
+ bExpressionCont* bexpcont = (bExpressionCont*) bcontr->data;
+ STR_String expressiontext = STR_String(bexpcont->str);
+ if (expressiontext.Length() > 0)
+ {
+ gamecontroller = new SCA_ExpressionController(gameobj,expressiontext);
+ LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter);
+
+ }
+ break;
+ }
+ case CONT_PYTHON:
+ {
+
+ // we should create a Python controller here
+
+ SCA_PythonController* pyctrl = new SCA_PythonController(gameobj);
+ gamecontroller = pyctrl;
+
+ bPythonCont* pycont = (bPythonCont*) bcontr->data;
+ pyctrl->SetDictionary(pythondictionary);
+
+ if (pycont->text)
+ {
+ char *buf;
+ // this is some blender specific code
+ buf= txt_to_buf(pycont->text);
+ if (buf)
+ {
+ pyctrl->SetScriptText(STR_String(buf));
+ pyctrl->SetScriptName(pycont->text->id.name+2);
+ MEM_freeN(buf);
+ }
+
+ }
+
+ LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter);
+ break;
+ }
+ default:
+ {
+
+ }
+ }
+
+ if (gamecontroller)
+ {
+ gamecontroller->SetExecutePriority(executePriority++);
+ STR_String uniquename = bcontr->name;
+ uniquename += "#CONTR#";
+ uniqueint++;
+ CIntValue* uniqueval = new CIntValue(uniqueint);
+ uniquename += uniqueval->GetText();
+ uniqueval->Release();
+ gamecontroller->SetName(uniquename);
+ gameobj->AddController(gamecontroller);
+
+ converter->RegisterGameController(gamecontroller, bcontr);
+ }
+
+ bcontr = bcontr->next;
+ }
+
+}
diff --git a/source/gameengine/Converter/KX_ConvertControllers.h b/source/gameengine/Converter/KX_ConvertControllers.h
new file mode 100644
index 00000000000..3c2b45bddd0
--- /dev/null
+++ b/source/gameengine/Converter/KX_ConvertControllers.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 __KX_CONVERTCONTROLLERS_H
+#define __KX_CONVERTCONTROLLERS_H
+
+#include "KX_Python.h"
+
+void BL_ConvertControllers(
+ struct Object* blenderobject,
+ class KX_GameObject* gameobj,
+ class SCA_LogicManager* logicmgr,
+ PyObject* pythondictionary,
+ int & executePriority,
+ int activeLayerBitInfo,
+ bool isInActiveLayer,
+ class KX_BlenderSceneConverter* converter
+);
+
+
+#endif //__KX_CONVERTCONTROLLERS_H
+
diff --git a/source/gameengine/Converter/KX_ConvertProperties.cpp b/source/gameengine/Converter/KX_ConvertProperties.cpp
new file mode 100644
index 00000000000..a1807732416
--- /dev/null
+++ b/source/gameengine/Converter/KX_ConvertProperties.cpp
@@ -0,0 +1,137 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_ConvertProperties.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* This little block needed for linking to Blender... */
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include "DNA_object_types.h"
+#include "DNA_property_types.h"
+/* end of blender include block */
+
+#include "Value.h"
+#include "VectorValue.h"
+#include "BoolValue.h"
+#include "StringValue.h"
+#include "FloatValue.h"
+#include "KX_GameObject.h"
+//#include "ListValue.h"
+#include "IntValue.h"
+#include "SCA_TimeEventManager.h"
+#include "SCA_IScene.h"
+
+
+void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventManager* timemgr,SCA_IScene* scene, bool isInActiveLayer)
+{
+
+ bProperty* prop = (bProperty*)object->prop.first;
+ CValue* propval;
+ bool show_debug_info;
+ while(prop)
+ {
+
+ propval = NULL;
+ show_debug_info = bool (prop->flag & PROP_DEBUG);
+
+ switch(prop->type) {
+ case PROP_BOOL:
+ {
+ propval = new CBoolValue((bool)(prop->data != 0));
+ gameobj->SetProperty(prop->name,propval);
+ //promp->poin= &prop->data;
+ break;
+ }
+ case PROP_INT:
+ {
+ propval = new CIntValue((int)prop->data);
+ gameobj->SetProperty(prop->name,propval);
+ break;
+ }
+ case PROP_FLOAT:
+ {
+ //prop->poin= &prop->data;
+ float floatprop = *((float*)&prop->data);
+ propval = new CFloatValue(floatprop);
+ gameobj->SetProperty(prop->name,propval);
+ }
+ break;
+ case PROP_STRING:
+ {
+ //prop->poin= callocN(MAX_PROPSTRING, "property string");
+ propval = new CStringValue((char*)prop->poin,"");
+ gameobj->SetProperty(prop->name,propval);
+ break;
+ }
+ case PROP_TIME:
+ {
+ float floatprop = *((float*)&prop->data);
+
+ CValue* timeval = new CFloatValue(floatprop);
+ // set a subproperty called 'timer' so that
+ // we can register the replica of this property
+ // at the time a game object is replicated (AddObjectActuator triggers this)
+
+ timeval->SetProperty("timer",new CBoolValue(true));
+ if (isInActiveLayer)
+ {
+ timemgr->AddTimeProperty(timeval);
+ }
+
+ propval = timeval;
+ gameobj->SetProperty(prop->name,timeval);
+
+ }
+ default:
+ {
+ // todo make an assert etc.
+ }
+ }
+
+ if (propval)
+ {
+ if (show_debug_info)
+ {
+ scene->AddDebugProperty(gameobj,STR_String(prop->name));
+ }
+ }
+
+ prop = prop->next;
+ }
+
+
+}
diff --git a/source/gameengine/Converter/KX_ConvertProperties.h b/source/gameengine/Converter/KX_ConvertProperties.h
new file mode 100644
index 00000000000..eb44f7b7d35
--- /dev/null
+++ b/source/gameengine/Converter/KX_ConvertProperties.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 *****
+ */
+#ifndef __KX_CONVERTPROPERTIES
+#define __KX_CONVERTPROPERTIES
+
+void BL_ConvertProperties(struct Object* object,
+ class KX_GameObject* gameobj,
+ class SCA_TimeEventManager* timemgr,
+ class SCA_IScene* scene,
+ bool isInActiveLayer);
+
+#endif //__KX_CONVERTPROPERTIES
+
diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp
new file mode 100644
index 00000000000..40c15302553
--- /dev/null
+++ b/source/gameengine/Converter/KX_ConvertSensors.cpp
@@ -0,0 +1,740 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Conversion of Blender data blocks to KX sensor system
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif //WIN32
+
+#include "KX_BlenderSceneConverter.h"
+#include "KX_ConvertSensors.h"
+
+/* This little block needed for linking to Blender... */
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_actuator_types.h" /* for SENS_ALL_KEYS ? this define is
+probably misplaced */
+/* end of blender include block */
+
+#include "RAS_IPolygonMaterial.h"
+// Sensors
+#include "KX_GameObject.h"
+#include "RAS_MeshObject.h"
+#include "SCA_KeyboardSensor.h"
+#include "SCA_MouseSensor.h"
+#include "SCA_AlwaysSensor.h"
+#include "KX_TouchSensor.h"
+#include "KX_NearSensor.h"
+#include "KX_RadarSensor.h"
+#include "KX_MouseFocusSensor.h"
+#include "SCA_JoystickSensor.h"
+#include "KX_NetworkMessageSensor.h"
+
+
+#include "SCA_PropertySensor.h"
+#include "SCA_RandomSensor.h"
+#include "KX_RaySensor.h"
+#include "SCA_EventManager.h"
+#include "SCA_LogicManager.h"
+#include "KX_BlenderInputDevice.h"
+#include "KX_Scene.h"
+#include "IntValue.h"
+#include "KX_BlenderKeyboardDevice.h"
+#include "KX_BlenderGL.h"
+#include "RAS_ICanvas.h"
+#include "PHY_IPhysicsEnvironment.h"
+
+#include "KX_KetsjiEngine.h"
+#include "KX_BlenderSceneConverter.h"
+
+// this map is Blender specific: a conversion between blender and ketsji enums
+std::map<int,SCA_IInputDevice::KX_EnumInputs> gReverseKeyTranslateTable;
+
+
+void BL_ConvertSensors(struct Object* blenderobject,
+ class KX_GameObject* gameobj,
+ SCA_LogicManager* logicmgr,
+ KX_Scene* kxscene,
+ SCA_IInputDevice* keydev,
+ int & executePriority,
+ int activeLayerBitInfo,
+ bool isInActiveLayer,
+ RAS_ICanvas* canvas,
+ KX_BlenderSceneConverter* converter
+ )
+{
+
+
+
+ /* The reverse table. In order to not confuse ourselves, we */
+ /* immediately convert all events that come in to KX codes. */
+ gReverseKeyTranslateTable[LEFTMOUSE ] = SCA_IInputDevice::KX_LEFTMOUSE;
+ gReverseKeyTranslateTable[MIDDLEMOUSE ] = SCA_IInputDevice::KX_MIDDLEMOUSE;
+ gReverseKeyTranslateTable[RIGHTMOUSE ] = SCA_IInputDevice::KX_RIGHTMOUSE;
+ gReverseKeyTranslateTable[WHEELUPMOUSE ] = SCA_IInputDevice::KX_WHEELUPMOUSE;
+ gReverseKeyTranslateTable[WHEELDOWNMOUSE ] = SCA_IInputDevice::KX_WHEELDOWNMOUSE;
+ gReverseKeyTranslateTable[MOUSEX ] = SCA_IInputDevice::KX_MOUSEX;
+ gReverseKeyTranslateTable[MOUSEY ] = SCA_IInputDevice::KX_MOUSEY;
+
+ // TIMERS
+
+ gReverseKeyTranslateTable[TIMER0 ] = SCA_IInputDevice::KX_TIMER0;
+ gReverseKeyTranslateTable[TIMER1 ] = SCA_IInputDevice::KX_TIMER1;
+ gReverseKeyTranslateTable[TIMER2 ] = SCA_IInputDevice::KX_TIMER2;
+ gReverseKeyTranslateTable[TIMER3 ] = SCA_IInputDevice::KX_TIMER3;
+
+ // SYSTEM
+
+ gReverseKeyTranslateTable[KEYBD ] = SCA_IInputDevice::KX_KEYBD;
+ gReverseKeyTranslateTable[RAWKEYBD ] = SCA_IInputDevice::KX_RAWKEYBD;
+ gReverseKeyTranslateTable[REDRAW ] = SCA_IInputDevice::KX_REDRAW;
+ gReverseKeyTranslateTable[INPUTCHANGE ] = SCA_IInputDevice::KX_INPUTCHANGE;
+ gReverseKeyTranslateTable[QFULL ] = SCA_IInputDevice::KX_QFULL;
+ gReverseKeyTranslateTable[WINFREEZE ] = SCA_IInputDevice::KX_WINFREEZE;
+ gReverseKeyTranslateTable[WINTHAW ] = SCA_IInputDevice::KX_WINTHAW;
+ gReverseKeyTranslateTable[WINCLOSE ] = SCA_IInputDevice::KX_WINCLOSE;
+ gReverseKeyTranslateTable[WINQUIT ] = SCA_IInputDevice::KX_WINQUIT;
+ gReverseKeyTranslateTable[Q_FIRSTTIME ] = SCA_IInputDevice::KX_Q_FIRSTTIME;
+
+ // standard keyboard
+
+ gReverseKeyTranslateTable[AKEY ] = SCA_IInputDevice::KX_AKEY;
+ gReverseKeyTranslateTable[BKEY ] = SCA_IInputDevice::KX_BKEY;
+ gReverseKeyTranslateTable[CKEY ] = SCA_IInputDevice::KX_CKEY;
+ gReverseKeyTranslateTable[DKEY ] = SCA_IInputDevice::KX_DKEY;
+ gReverseKeyTranslateTable[EKEY ] = SCA_IInputDevice::KX_EKEY;
+ gReverseKeyTranslateTable[FKEY ] = SCA_IInputDevice::KX_FKEY;
+ gReverseKeyTranslateTable[GKEY ] = SCA_IInputDevice::KX_GKEY;
+ gReverseKeyTranslateTable[HKEY ] = SCA_IInputDevice::KX_HKEY;
+ gReverseKeyTranslateTable[IKEY ] = SCA_IInputDevice::KX_IKEY;
+ gReverseKeyTranslateTable[JKEY ] = SCA_IInputDevice::KX_JKEY;
+ gReverseKeyTranslateTable[KKEY ] = SCA_IInputDevice::KX_KKEY;
+ gReverseKeyTranslateTable[LKEY ] = SCA_IInputDevice::KX_LKEY;
+ gReverseKeyTranslateTable[MKEY ] = SCA_IInputDevice::KX_MKEY;
+ gReverseKeyTranslateTable[NKEY ] = SCA_IInputDevice::KX_NKEY;
+ gReverseKeyTranslateTable[OKEY ] = SCA_IInputDevice::KX_OKEY;
+ gReverseKeyTranslateTable[PKEY ] = SCA_IInputDevice::KX_PKEY;
+ gReverseKeyTranslateTable[QKEY ] = SCA_IInputDevice::KX_QKEY;
+ gReverseKeyTranslateTable[RKEY ] = SCA_IInputDevice::KX_RKEY;
+ gReverseKeyTranslateTable[SKEY ] = SCA_IInputDevice::KX_SKEY;
+ gReverseKeyTranslateTable[TKEY ] = SCA_IInputDevice::KX_TKEY;
+ gReverseKeyTranslateTable[UKEY ] = SCA_IInputDevice::KX_UKEY;
+ gReverseKeyTranslateTable[VKEY ] = SCA_IInputDevice::KX_VKEY;
+ gReverseKeyTranslateTable[WKEY ] = SCA_IInputDevice::KX_WKEY;
+ gReverseKeyTranslateTable[XKEY ] = SCA_IInputDevice::KX_XKEY;
+ gReverseKeyTranslateTable[YKEY ] = SCA_IInputDevice::KX_YKEY;
+ gReverseKeyTranslateTable[ZKEY ] = SCA_IInputDevice::KX_ZKEY;
+
+ gReverseKeyTranslateTable[ZEROKEY ] = SCA_IInputDevice::KX_ZEROKEY;
+ gReverseKeyTranslateTable[ONEKEY ] = SCA_IInputDevice::KX_ONEKEY;
+ gReverseKeyTranslateTable[TWOKEY ] = SCA_IInputDevice::KX_TWOKEY;
+ gReverseKeyTranslateTable[THREEKEY ] = SCA_IInputDevice::KX_THREEKEY;
+ gReverseKeyTranslateTable[FOURKEY ] = SCA_IInputDevice::KX_FOURKEY;
+ gReverseKeyTranslateTable[FIVEKEY ] = SCA_IInputDevice::KX_FIVEKEY;
+ gReverseKeyTranslateTable[SIXKEY ] = SCA_IInputDevice::KX_SIXKEY;
+ gReverseKeyTranslateTable[SEVENKEY ] = SCA_IInputDevice::KX_SEVENKEY;
+ gReverseKeyTranslateTable[EIGHTKEY ] = SCA_IInputDevice::KX_EIGHTKEY;
+ gReverseKeyTranslateTable[NINEKEY ] = SCA_IInputDevice::KX_NINEKEY;
+
+ gReverseKeyTranslateTable[CAPSLOCKKEY ] = SCA_IInputDevice::KX_CAPSLOCKKEY;
+
+ gReverseKeyTranslateTable[LEFTCTRLKEY ] = SCA_IInputDevice::KX_LEFTCTRLKEY;
+ gReverseKeyTranslateTable[LEFTALTKEY ] = SCA_IInputDevice::KX_LEFTALTKEY;
+ gReverseKeyTranslateTable[RIGHTALTKEY ] = SCA_IInputDevice::KX_RIGHTALTKEY;
+ gReverseKeyTranslateTable[RIGHTCTRLKEY ] = SCA_IInputDevice::KX_RIGHTCTRLKEY;
+ gReverseKeyTranslateTable[RIGHTSHIFTKEY ] = SCA_IInputDevice::KX_RIGHTSHIFTKEY;
+ gReverseKeyTranslateTable[LEFTSHIFTKEY ] = SCA_IInputDevice::KX_LEFTSHIFTKEY;
+
+ gReverseKeyTranslateTable[ESCKEY ] = SCA_IInputDevice::KX_ESCKEY;
+ gReverseKeyTranslateTable[TABKEY ] = SCA_IInputDevice::KX_TABKEY;
+ gReverseKeyTranslateTable[RETKEY ] = SCA_IInputDevice::KX_RETKEY;
+ gReverseKeyTranslateTable[SPACEKEY ] = SCA_IInputDevice::KX_SPACEKEY;
+ gReverseKeyTranslateTable[LINEFEEDKEY ] = SCA_IInputDevice::KX_LINEFEEDKEY;
+ gReverseKeyTranslateTable[BACKSPACEKEY ] = SCA_IInputDevice::KX_BACKSPACEKEY;
+ gReverseKeyTranslateTable[DELKEY ] = SCA_IInputDevice::KX_DELKEY;
+ gReverseKeyTranslateTable[SEMICOLONKEY ] = SCA_IInputDevice::KX_SEMICOLONKEY;
+ gReverseKeyTranslateTable[PERIODKEY ] = SCA_IInputDevice::KX_PERIODKEY;
+ gReverseKeyTranslateTable[COMMAKEY ] = SCA_IInputDevice::KX_COMMAKEY;
+ gReverseKeyTranslateTable[QUOTEKEY ] = SCA_IInputDevice::KX_QUOTEKEY;
+ gReverseKeyTranslateTable[ACCENTGRAVEKEY ] = SCA_IInputDevice::KX_ACCENTGRAVEKEY;
+ gReverseKeyTranslateTable[MINUSKEY ] = SCA_IInputDevice::KX_MINUSKEY;
+ gReverseKeyTranslateTable[SLASHKEY ] = SCA_IInputDevice::KX_SLASHKEY;
+ gReverseKeyTranslateTable[BACKSLASHKEY ] = SCA_IInputDevice::KX_BACKSLASHKEY;
+ gReverseKeyTranslateTable[EQUALKEY ] = SCA_IInputDevice::KX_EQUALKEY;
+ gReverseKeyTranslateTable[LEFTBRACKETKEY ] = SCA_IInputDevice::KX_LEFTBRACKETKEY;
+ gReverseKeyTranslateTable[RIGHTBRACKETKEY ] = SCA_IInputDevice::KX_RIGHTBRACKETKEY;
+
+ gReverseKeyTranslateTable[LEFTARROWKEY ] = SCA_IInputDevice::KX_LEFTARROWKEY;
+ gReverseKeyTranslateTable[DOWNARROWKEY ] = SCA_IInputDevice::KX_DOWNARROWKEY;
+ gReverseKeyTranslateTable[RIGHTARROWKEY ] = SCA_IInputDevice::KX_RIGHTARROWKEY;
+ gReverseKeyTranslateTable[UPARROWKEY ] = SCA_IInputDevice::KX_UPARROWKEY;
+
+ gReverseKeyTranslateTable[PAD2 ] = SCA_IInputDevice::KX_PAD2;
+ gReverseKeyTranslateTable[PAD4 ] = SCA_IInputDevice::KX_PAD4;
+ gReverseKeyTranslateTable[PAD6 ] = SCA_IInputDevice::KX_PAD6;
+ gReverseKeyTranslateTable[PAD8 ] = SCA_IInputDevice::KX_PAD8;
+
+ gReverseKeyTranslateTable[PAD1 ] = SCA_IInputDevice::KX_PAD1;
+ gReverseKeyTranslateTable[PAD3 ] = SCA_IInputDevice::KX_PAD3;
+ gReverseKeyTranslateTable[PAD5 ] = SCA_IInputDevice::KX_PAD5;
+ gReverseKeyTranslateTable[PAD7 ] = SCA_IInputDevice::KX_PAD7;
+ gReverseKeyTranslateTable[PAD9 ] = SCA_IInputDevice::KX_PAD9;
+
+ gReverseKeyTranslateTable[PADPERIOD ] = SCA_IInputDevice::KX_PADPERIOD;
+ gReverseKeyTranslateTable[PADSLASHKEY ] = SCA_IInputDevice::KX_PADSLASHKEY;
+ gReverseKeyTranslateTable[PADASTERKEY ] = SCA_IInputDevice::KX_PADASTERKEY;
+
+ gReverseKeyTranslateTable[PAD0 ] = SCA_IInputDevice::KX_PAD0;
+ gReverseKeyTranslateTable[PADMINUS ] = SCA_IInputDevice::KX_PADMINUS;
+ gReverseKeyTranslateTable[PADENTER ] = SCA_IInputDevice::KX_PADENTER;
+ gReverseKeyTranslateTable[PADPLUSKEY ] = SCA_IInputDevice::KX_PADPLUSKEY;
+
+
+ gReverseKeyTranslateTable[F1KEY ] = SCA_IInputDevice::KX_F1KEY;
+ gReverseKeyTranslateTable[F2KEY ] = SCA_IInputDevice::KX_F2KEY;
+ gReverseKeyTranslateTable[F3KEY ] = SCA_IInputDevice::KX_F3KEY;
+ gReverseKeyTranslateTable[F4KEY ] = SCA_IInputDevice::KX_F4KEY;
+ gReverseKeyTranslateTable[F5KEY ] = SCA_IInputDevice::KX_F5KEY;
+ gReverseKeyTranslateTable[F6KEY ] = SCA_IInputDevice::KX_F6KEY;
+ gReverseKeyTranslateTable[F7KEY ] = SCA_IInputDevice::KX_F7KEY;
+ gReverseKeyTranslateTable[F8KEY ] = SCA_IInputDevice::KX_F8KEY;
+ gReverseKeyTranslateTable[F9KEY ] = SCA_IInputDevice::KX_F9KEY;
+ gReverseKeyTranslateTable[F10KEY ] = SCA_IInputDevice::KX_F10KEY;
+ gReverseKeyTranslateTable[F11KEY ] = SCA_IInputDevice::KX_F11KEY;
+ gReverseKeyTranslateTable[F12KEY ] = SCA_IInputDevice::KX_F12KEY;
+
+ gReverseKeyTranslateTable[PAUSEKEY ] = SCA_IInputDevice::KX_PAUSEKEY;
+ gReverseKeyTranslateTable[INSERTKEY ] = SCA_IInputDevice::KX_INSERTKEY;
+ gReverseKeyTranslateTable[HOMEKEY ] = SCA_IInputDevice::KX_HOMEKEY;
+ gReverseKeyTranslateTable[PAGEUPKEY ] = SCA_IInputDevice::KX_PAGEUPKEY;
+ gReverseKeyTranslateTable[PAGEDOWNKEY ] = SCA_IInputDevice::KX_PAGEDOWNKEY;
+ gReverseKeyTranslateTable[ENDKEY ] = SCA_IInputDevice::KX_ENDKEY;
+
+ int uniqueint = 0;
+ bSensor* sens = (bSensor*)blenderobject->sensors.first;
+ bool pos_pulsemode = false;
+ bool neg_pulsemode = false;
+ int frequency = 0;
+ bool invert = false;
+
+ while(sens)
+ {
+ SCA_ISensor* gamesensor=NULL;
+ /* All sensors have a pulse toggle, frequency, and invert field. */
+ /* These are extracted here, and set when the sensor is added to the */
+ /* list. */
+ pos_pulsemode = (sens->pulse & SENS_PULSE_REPEAT)!=0;
+ neg_pulsemode = (sens->pulse & SENS_NEG_PULSE_MODE)!=0;
+
+ frequency = sens->freq;
+ invert = !(sens->invert == 0);
+
+ switch (sens->type)
+ {
+ case SENS_ALWAYS:
+ {
+
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::ALWAYS_EVENTMGR);
+ if (eventmgr)
+ {
+ gamesensor = new SCA_AlwaysSensor(eventmgr, gameobj);
+ }
+
+ break;
+ }
+
+ case SENS_COLLISION:
+ {
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR);
+ if (eventmgr)
+ {
+ // collision sensor can sense both materials and properties.
+
+ bool bFindMaterial = false;
+
+ bCollisionSensor* blendertouchsensor = (bCollisionSensor*)sens->data;
+
+ bFindMaterial = (blendertouchsensor->mode
+ & SENS_COLLISION_MATERIAL);
+
+
+ STR_String touchPropOrMatName = ( bFindMaterial ?
+ blendertouchsensor->materialName:
+ (blendertouchsensor->name ? blendertouchsensor->name: ""));
+
+
+ if (gameobj->GetPhysicsController())
+ {
+ gamesensor = new KX_TouchSensor(eventmgr,
+ gameobj,
+ bFindMaterial,
+ touchPropOrMatName);
+ }
+
+ }
+
+ break;
+ }
+ case SENS_TOUCH:
+ {
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR);
+ if (eventmgr)
+ {
+ STR_String touchpropertyname;
+ bTouchSensor* blendertouchsensor = (bTouchSensor*)sens->data;
+
+ if (blendertouchsensor->ma)
+ {
+ touchpropertyname = (char*) (blendertouchsensor->ma->id.name+2);
+ }
+ bool bFindMaterial = true;
+ if (gameobj->GetPhysicsController())
+ {
+ gamesensor = new KX_TouchSensor(eventmgr,
+ gameobj,
+ bFindMaterial,
+ touchpropertyname);
+ }
+ }
+ break;
+ }
+ case SENS_MESSAGE:
+ {
+ KX_NetworkEventManager* eventmgr = (KX_NetworkEventManager*)
+ logicmgr->FindEventManager(SCA_EventManager::NETWORK_EVENTMGR);
+ if (eventmgr) {
+ bMessageSensor* msgSens = (bMessageSensor*) sens->data;
+
+ /* Get our NetworkScene */
+ NG_NetworkScene *NetworkScene = kxscene->GetNetworkScene();
+ /* filter on the incoming subjects, might be empty */
+ STR_String subject = (msgSens->subject
+ ? (char*)msgSens->subject
+ : "");
+
+ gamesensor = new KX_NetworkMessageSensor(
+ eventmgr, // our eventmanager
+ NetworkScene, // our NetworkScene
+ gameobj, // the sensor controlling object
+ subject); // subject to filter on
+ }
+ break;
+ }
+ case SENS_NEAR:
+ {
+
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR);
+ if (eventmgr)
+ {
+ STR_String nearpropertyname;
+ bNearSensor* blendernearsensor = (bNearSensor*)sens->data;
+ if (blendernearsensor->name)
+ {
+ // only objects that own this property will be taken into account
+ nearpropertyname = (char*) blendernearsensor->name;
+ }
+
+ //DT_ShapeHandle shape = DT_Sphere(0.0);
+
+ // this sumoObject is not deleted by a gameobj, so delete it ourself
+ // later (memleaks)!
+ float radius = blendernearsensor->dist;
+ PHY__Vector3 pos;
+ const MT_Vector3& wpos = gameobj->NodeGetWorldPosition();
+ pos[0] = wpos[0];
+ pos[1] = wpos[1];
+ pos[2] = wpos[2];
+ pos[3] = 0.f;
+ bool bFindMaterial = false;
+ PHY_IPhysicsController* physCtrl = kxscene->GetPhysicsEnvironment()->CreateSphereController(radius,pos);
+
+ if (isInActiveLayer)
+ kxscene->GetPhysicsEnvironment()->addSensor(physCtrl);
+
+
+
+ gamesensor = new KX_NearSensor(eventmgr,gameobj,
+ blendernearsensor->dist,
+ blendernearsensor->resetdist,
+ bFindMaterial,
+ nearpropertyname,kxscene,
+ physCtrl
+ );
+
+ }
+ break;
+ }
+
+
+ case SENS_KEYBOARD:
+ {
+ /* temporary input device, for converting the code for the keyboard sensor */
+
+ bKeyboardSensor* blenderkeybdsensor = (bKeyboardSensor*)sens->data;
+ SCA_KeyboardManager* eventmgr = (SCA_KeyboardManager*) logicmgr->FindEventManager(SCA_EventManager::KEYBOARD_EVENTMGR);
+ if (eventmgr)
+ {
+ gamesensor = new SCA_KeyboardSensor(eventmgr,
+ gReverseKeyTranslateTable[blenderkeybdsensor->key],
+ blenderkeybdsensor->qual,
+ blenderkeybdsensor->qual2,
+ (blenderkeybdsensor->type == SENS_ALL_KEYS),
+ blenderkeybdsensor->targetName,
+ blenderkeybdsensor->toggleName,
+ gameobj); // blenderkeybdsensor->pad);
+
+ }
+
+ break;
+ }
+ case SENS_MOUSE:
+ {
+ int keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_NODEF;
+ int trackfocus = 0;
+ bMouseSensor *bmouse = (bMouseSensor *)sens->data;
+
+ /* There are two main types of mouse sensors. If there is
+ * no focus-related behaviour requested, we can make do
+ * with a basic sensor. This cuts down memory usage and
+ * gives a slight performance gain. */
+
+ SCA_MouseManager *eventmgr
+ = (SCA_MouseManager*) logicmgr->FindEventManager(SCA_EventManager::MOUSE_EVENTMGR);
+ if (eventmgr) {
+
+ /* Determine key mode. There is at most one active mode. */
+ switch (bmouse->type) {
+ case BL_SENS_MOUSE_LEFT_BUTTON:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_LEFTBUTTON;
+ break;
+ case BL_SENS_MOUSE_MIDDLE_BUTTON:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_MIDDLEBUTTON;
+ break;
+ case BL_SENS_MOUSE_RIGHT_BUTTON:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_RIGHTBUTTON;
+ break;
+ case BL_SENS_MOUSE_WHEEL_UP:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_WHEELUP;
+ break;
+ case BL_SENS_MOUSE_WHEEL_DOWN:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_WHEELDOWN;
+ break;
+ case BL_SENS_MOUSE_MOVEMENT:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_MOVEMENT;
+ break;
+ case BL_SENS_MOUSE_MOUSEOVER:
+ trackfocus = 1;
+ break;
+ case BL_SENS_MOUSE_MOUSEOVER_ANY:
+ trackfocus = 2;
+ break;
+
+ default:
+ ; /* error */
+ }
+
+ /* initial mouse position */
+ int startx = canvas->GetWidth()/2;
+ int starty = canvas->GetHeight()/2;
+
+ if (!trackfocus) {
+ /* plain, simple mouse sensor */
+ gamesensor = new SCA_MouseSensor(eventmgr,
+ startx,starty,
+ keytype,
+ gameobj);
+ } else {
+ /* give us a focus-aware sensor */
+ gamesensor = new KX_MouseFocusSensor(eventmgr,
+ startx,
+ starty,
+ keytype,
+ trackfocus,
+ canvas,
+ kxscene,
+ gameobj);
+ }
+ } else {
+ // cout << "\n Could't find mouse event manager..."; - should throw an error here...
+ }
+ break;
+ }
+ case SENS_PROPERTY:
+ {
+ bPropertySensor* blenderpropsensor = (bPropertySensor*) sens->data;
+ SCA_EventManager* eventmgr
+ = logicmgr->FindEventManager(SCA_EventManager::PROPERTY_EVENTMGR);
+ if (eventmgr)
+ {
+ STR_String propname=blenderpropsensor->name;
+ STR_String propval=blenderpropsensor->value;
+ STR_String propmaxval=blenderpropsensor->maxvalue;
+
+ SCA_PropertySensor::KX_PROPSENSOR_TYPE
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_NODEF;
+
+ /* Better do an explicit conversion here! (was implicit */
+ /* before...) */
+ switch(blenderpropsensor->type) {
+ case SENS_PROP_EQUAL:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_EQUAL;
+ break;
+ case SENS_PROP_NEQUAL:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_NOTEQUAL;
+ break;
+ case SENS_PROP_INTERVAL:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_INTERVAL;
+ break;
+ case SENS_PROP_CHANGED:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_CHANGED;
+ break;
+ case SENS_PROP_EXPRESSION:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_EXPRESSION;
+ /* error */
+ break;
+ default:
+ ; /* error */
+ }
+ gamesensor = new SCA_PropertySensor(eventmgr,gameobj,propname,propval,propmaxval,propchecktype);
+ }
+
+ break;
+ }
+
+ case SENS_RADAR:
+ {
+
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR);
+ if (eventmgr)
+ {
+ STR_String radarpropertyname;
+ STR_String touchpropertyname;
+ bRadarSensor* blenderradarsensor = (bRadarSensor*) sens->data;
+
+ int radaraxis = blenderradarsensor->axis;
+
+ if (blenderradarsensor->name)
+ {
+ // only objects that own this property will be taken into account
+ radarpropertyname = (char*) blenderradarsensor->name;
+ }
+
+ MT_Scalar coneheight = blenderradarsensor->range;
+
+ // janco: the angle was doubled, so should I divide the factor in 2
+ // or the blenderradarsensor->angle?
+ // nzc: the angle is the opening angle. We need to init with
+ // the axis-hull angle,so /2.0.
+ MT_Scalar factor = tan(MT_radians((blenderradarsensor->angle)/2.0));
+ //MT_Scalar coneradius = coneheight * (factor / 2);
+ MT_Scalar coneradius = coneheight * factor;
+
+
+ // this sumoObject is not deleted by a gameobj, so delete it ourself
+ // later (memleaks)!
+ MT_Scalar smallmargin = 0.0;
+ MT_Scalar largemargin = 0.0;
+
+ bool bFindMaterial = false;
+ PHY_IPhysicsController* ctrl = kxscene->GetPhysicsEnvironment()->CreateConeController(coneradius,coneheight);
+
+ gamesensor = new KX_RadarSensor(
+ eventmgr,
+ gameobj,
+ ctrl,
+ coneradius,
+ coneheight,
+ radaraxis,
+ smallmargin,
+ largemargin,
+ bFindMaterial,
+ radarpropertyname,
+ kxscene);
+
+ }
+
+ break;
+ }
+ case SENS_RAY:
+ {
+ bRaySensor* blenderraysensor = (bRaySensor*) sens->data;
+
+ //blenderradarsensor->angle;
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::RAY_EVENTMGR);
+ if (eventmgr)
+ {
+ bool bFindMaterial = (blenderraysensor->mode & SENS_COLLISION_MATERIAL);
+
+ STR_String checkname = (bFindMaterial? blenderraysensor->matname : blenderraysensor->propname);
+
+ // don't want to get rays of length 0.0 or so
+ double distance = (blenderraysensor->range < 0.01 ? 0.01 : blenderraysensor->range );
+ int axis = blenderraysensor->axisflag;
+
+
+ gamesensor = new KX_RaySensor(eventmgr,
+ gameobj,
+ checkname,
+ bFindMaterial,
+ distance,
+ axis,
+ kxscene);
+
+ }
+ break;
+ }
+
+ case SENS_RANDOM:
+ {
+ bRandomSensor* blenderrndsensor = (bRandomSensor*) sens->data;
+ // some files didn't write randomsensor, avoid crash now for NULL ptr's
+ if (blenderrndsensor)
+ {
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::RANDOM_EVENTMGR);
+ if (eventmgr)
+ {
+ int randomSeed = blenderrndsensor->seed;
+ gamesensor = new SCA_RandomSensor(eventmgr, gameobj, randomSeed);
+ }
+ }
+ break;
+ }
+ case SENS_JOYSTICK:
+ {
+ int joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_NODEF;
+
+ bJoystickSensor* bjoy = (bJoystickSensor*) sens->data;
+
+ SCA_JoystickManager *eventmgr
+ = (SCA_JoystickManager*) logicmgr->FindEventManager(SCA_EventManager::JOY_EVENTMGR);
+ if (eventmgr)
+ {
+ int axis =0;
+ int axisf =0;
+ int button =0;
+ int buttonf =0;
+ int hat =0;
+ int hatf =0;
+ int prec =0;
+
+ switch(bjoy->type)
+ {
+ case SENS_JOY_AXIS:
+ axis = bjoy->axis;
+ axisf = bjoy->axisf;
+ prec = bjoy->precision;
+ joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_AXIS;
+ break;
+ case SENS_JOY_BUTTON:
+ button = bjoy->button;
+ buttonf = bjoy->buttonf;
+ joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_BUTTON;
+ break;
+ case SENS_JOY_HAT:
+ hat = bjoy->hat;
+ hatf = bjoy->hatf;
+ joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_HAT;
+ break;
+ default:
+ printf("Error: bad case statement\n");
+ break;
+ }
+ gamesensor = new SCA_JoystickSensor(
+ eventmgr,
+ gameobj,
+ joysticktype,
+ axis,axisf,
+ prec,
+ button,buttonf,
+ hat,hatf);
+ }
+ else
+ {
+ printf("Error there was a problem finding the event manager\n");
+ }
+
+ break;
+ }
+ default:
+ {
+ }
+ }
+
+ if (gamesensor)
+ {
+ gamesensor->SetExecutePriority(executePriority++);
+ STR_String uniquename = sens->name;
+ uniquename += "#SENS#";
+ uniqueint++;
+ CIntValue* uniqueval = new CIntValue(uniqueint);
+ uniquename += uniqueval->GetText();
+ uniqueval->Release();
+
+ /* Conversion succeeded, so we can set the generic props here. */
+ gamesensor->SetPulseMode(pos_pulsemode,
+ neg_pulsemode,
+ frequency);
+ gamesensor->SetInvert(invert);
+ gamesensor->SetName(STR_String(sens->name));
+
+ gameobj->AddSensor(gamesensor);
+
+ // only register to manager if it's in an active layer
+
+ if (isInActiveLayer)
+ gamesensor->RegisterToManager();
+
+
+ for (int i=0;i<sens->totlinks;i++)
+ {
+ bController* linkedcont = (bController*) sens->links[i];
+ SCA_IController* gamecont = converter->FindGameController(linkedcont);
+
+ if (gamecont) {
+ logicmgr->RegisterToSensor(gamecont,gamesensor);
+ }
+ }
+
+ }
+ sens=sens->next;
+ }
+}
+
diff --git a/source/gameengine/Converter/KX_ConvertSensors.h b/source/gameengine/Converter/KX_ConvertSensors.h
new file mode 100644
index 00000000000..9878d4a7a09
--- /dev/null
+++ b/source/gameengine/Converter/KX_ConvertSensors.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 __KX_CONVERTSENSOR_H
+#define __KX_CONVERTSENSOR_H
+
+void BL_ConvertSensors(struct Object* blenderobject,
+ class KX_GameObject* gameobj,
+ class SCA_LogicManager* logicmgr,
+ class KX_Scene* kxscene,
+ class SCA_IInputDevice* keydev,
+ int & executePriority ,
+ int activeLayerBitInfo,
+ bool isInActiveLayer,
+ class RAS_ICanvas* canvas,
+ class KX_BlenderSceneConverter* converter);
+
+#endif //__KX_CONVERTSENSOR_H
+
diff --git a/source/gameengine/Converter/KX_IpoConvert.cpp b/source/gameengine/Converter/KX_IpoConvert.cpp
new file mode 100644
index 00000000000..defcdffb6fc
--- /dev/null
+++ b/source/gameengine/Converter/KX_IpoConvert.cpp
@@ -0,0 +1,757 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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
+
+// don't show stl-warnings
+#pragma warning (disable:4786)
+#endif
+
+
+#include "KX_GameObject.h"
+#include "KX_IpoConvert.h"
+#include "KX_IInterpolator.h"
+#include "KX_ScalarInterpolator.h"
+
+#include "KX_BlenderScalarInterpolator.h"
+#include "KX_BlenderSceneConverter.h"
+
+
+/* This little block needed for linking to Blender... */
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include "DNA_object_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_world_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_material_types.h"
+/* end of blender include block */
+
+#include "KX_IPO_SGController.h"
+#include "KX_LightIpoSGController.h"
+#include "KX_CameraIpoSGController.h"
+#include "KX_WorldIpoController.h"
+#include "KX_ObColorIpoSGController.h"
+#include "KX_MaterialIpoController.h"
+
+#include "SG_Node.h"
+
+static BL_InterpolatorList *GetIpoList(struct Ipo *for_ipo, KX_BlenderSceneConverter *converter) {
+ BL_InterpolatorList *ipoList= converter->FindInterpolatorList(for_ipo);
+
+ if (!ipoList) {
+ ipoList = new BL_InterpolatorList(for_ipo);
+ converter->RegisterInterpolatorList(ipoList, for_ipo);
+ }
+
+ return ipoList;
+}
+
+void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_BlenderSceneConverter *converter)
+{
+ if (blenderobject->ipo) {
+
+ KX_IpoSGController* ipocontr = new KX_IpoSGController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+
+ // For ipo_as_force, we need to know which SM object and Scene the
+ // object associated with this ipo is in. Is this already known here?
+ // I think not.... then it must be done later :(
+// ipocontr->SetSumoReference(gameobj->GetSumoScene(),
+// gameobj->GetSumoObject());
+
+ ipocontr->SetGameObject(gameobj);
+
+ ipocontr->GetIPOTransform().SetPosition(
+ MT_Point3(
+ blenderobject->loc[0]+blenderobject->dloc[0],
+ blenderobject->loc[1]+blenderobject->dloc[1],
+ blenderobject->loc[2]+blenderobject->dloc[2]
+ )
+ );
+ ipocontr->GetIPOTransform().SetEulerAngles(
+ MT_Vector3(
+ blenderobject->rot[0],
+ blenderobject->rot[1],
+ blenderobject->rot[2]
+ )
+ );
+ ipocontr->GetIPOTransform().SetScaling(
+ MT_Vector3(
+ blenderobject->size[0],
+ blenderobject->size[1],
+ blenderobject->size[2]
+ )
+ );
+
+ BL_InterpolatorList *ipoList= GetIpoList(blenderobject->ipo, converter);
+
+ // For each active channel in the ipoList add an
+ // interpolator to the game object.
+
+ KX_IScalarInterpolator *ipo;
+
+ ipo = ipoList->GetScalarInterpolator(OB_LOC_X);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetPosition()[0]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyPosition(true);
+
+ }
+
+ ipo = ipoList->GetScalarInterpolator(OB_LOC_Y);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetPosition()[1]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyPosition(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(OB_LOC_Z);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetPosition()[2]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyPosition(true);
+ }
+
+ // Master the art of cut & paste programming...
+
+ ipo = ipoList->GetScalarInterpolator(OB_DLOC_X);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetDeltaPosition()[0]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyPosition(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(OB_DLOC_Y);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetDeltaPosition()[1]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyPosition(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(OB_DLOC_Z);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetDeltaPosition()[2]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyPosition(true);
+ }
+
+ // Explore the finesse of reuse and slight modification
+
+ ipo = ipoList->GetScalarInterpolator(OB_ROT_X);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetEulerAngles()[0]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyOrientation(true);
+ }
+ ipo = ipoList->GetScalarInterpolator(OB_ROT_Y);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetEulerAngles()[1]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyOrientation(true);
+ }
+ ipo = ipoList->GetScalarInterpolator(OB_ROT_Z);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetEulerAngles()[2]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyOrientation(true);
+ }
+
+ // Hmmm, the need for a macro comes to mind...
+
+ ipo = ipoList->GetScalarInterpolator(OB_DROT_X);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[0]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyOrientation(true);
+ }
+ ipo = ipoList->GetScalarInterpolator(OB_DROT_Y);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[1]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyOrientation(true);
+ }
+ ipo = ipoList->GetScalarInterpolator(OB_DROT_Z);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[2]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyOrientation(true);
+ }
+
+ // Hang on, almost there...
+
+ ipo = ipoList->GetScalarInterpolator(OB_SIZE_X);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetScaling()[0]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyScaling(true);
+ }
+ ipo = ipoList->GetScalarInterpolator(OB_SIZE_Y);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetScaling()[1]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyScaling(true);
+ }
+ ipo = ipoList->GetScalarInterpolator(OB_SIZE_Z);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetScaling()[2]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyScaling(true);
+ }
+
+ // The last few...
+
+ ipo = ipoList->GetScalarInterpolator(OB_DSIZE_X);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetDeltaScaling()[0]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyScaling(true);
+ }
+ ipo = ipoList->GetScalarInterpolator(OB_DSIZE_Y);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetDeltaScaling()[1]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyScaling(true);
+ }
+ ipo = ipoList->GetScalarInterpolator(OB_DSIZE_Z);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &(ipocontr->GetIPOTransform().GetDeltaScaling()[2]),
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyScaling(true);
+ }
+
+ {
+ KX_ObColorIpoSGController* ipocontr=NULL;
+
+ ipo = ipoList->GetScalarInterpolator(OB_COL_R);
+ if (ipo)
+ {
+ if (!ipocontr)
+ {
+ ipocontr = new KX_ObColorIpoSGController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_rgba[0],
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+ ipo = ipoList->GetScalarInterpolator(OB_COL_G);
+ if (ipo)
+ {
+ if (!ipocontr)
+ {
+ ipocontr = new KX_ObColorIpoSGController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_rgba[1],
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+ ipo = ipoList->GetScalarInterpolator(OB_COL_B);
+ if (ipo)
+ {
+ if (!ipocontr)
+ {
+ ipocontr = new KX_ObColorIpoSGController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_rgba[2],
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+ ipo = ipoList->GetScalarInterpolator(OB_COL_A);
+ if (ipo)
+ {
+ if (!ipocontr)
+ {
+ ipocontr = new KX_ObColorIpoSGController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_rgba[3],
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+ }
+
+
+ }
+
+
+}
+
+void BL_ConvertLampIpos(struct Lamp* blenderlamp, KX_GameObject *lightobj,KX_BlenderSceneConverter *converter)
+{
+
+ if (blenderlamp->ipo) {
+
+ KX_LightIpoSGController* ipocontr = new KX_LightIpoSGController();
+ lightobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(lightobj->GetSGNode());
+
+ ipocontr->m_energy = blenderlamp->energy;
+ ipocontr->m_col_rgb[0] = blenderlamp->r;
+ ipocontr->m_col_rgb[1] = blenderlamp->g;
+ ipocontr->m_col_rgb[2] = blenderlamp->b;
+ ipocontr->m_dist = blenderlamp->dist;
+
+ BL_InterpolatorList *ipoList= GetIpoList(blenderlamp->ipo, converter);
+
+ // For each active channel in the ipoList add an
+ // interpolator to the game object.
+
+ KX_IScalarInterpolator *ipo;
+
+ ipo = ipoList->GetScalarInterpolator(LA_ENERGY);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_energy, ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyEnergy(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(LA_DIST);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_dist, ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyDist(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(LA_COL_R);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_col_rgb[0], ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyColor(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(LA_COL_G);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_col_rgb[1], ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyColor(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(LA_COL_B);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_col_rgb[2], ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyColor(true);
+ }
+ }
+}
+
+
+
+
+void BL_ConvertCameraIpos(struct Camera* blendercamera, KX_GameObject *cameraobj,KX_BlenderSceneConverter *converter)
+{
+
+ if (blendercamera->ipo) {
+
+ KX_CameraIpoSGController* ipocontr = new KX_CameraIpoSGController();
+ cameraobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(cameraobj->GetSGNode());
+
+ ipocontr->m_lens = blendercamera->lens;
+ ipocontr->m_clipstart = blendercamera->clipsta;
+ ipocontr->m_clipend = blendercamera->clipend;
+
+ BL_InterpolatorList *ipoList= GetIpoList(blendercamera->ipo, converter);
+
+ // For each active channel in the ipoList add an
+ // interpolator to the game object.
+
+ KX_IScalarInterpolator *ipo;
+
+ ipo = ipoList->GetScalarInterpolator(CAM_LENS);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_lens, ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyLens(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(CAM_STA);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_clipstart, ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyClipStart(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(CAM_END);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_clipend, ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyClipEnd(true);
+ }
+
+ }
+}
+
+
+void BL_ConvertWorldIpos(struct World* blenderworld,KX_BlenderSceneConverter *converter)
+{
+
+ if (blenderworld->ipo) {
+
+ KX_WorldIpoController* ipocontr = new KX_WorldIpoController();
+
+// Erwin, hook up the world ipo controller here
+// Gino: hook it up to what ?
+// is there a userinterface element for that ?
+// for now, we have some new python hooks to access the data, for a work-around
+
+ ipocontr->m_mist_start = blenderworld->miststa;
+ ipocontr->m_mist_dist = blenderworld->mistdist;
+ ipocontr->m_mist_rgb[0] = blenderworld->horr;
+ ipocontr->m_mist_rgb[1] = blenderworld->horg;
+ ipocontr->m_mist_rgb[2] = blenderworld->horb;
+
+ BL_InterpolatorList *ipoList= GetIpoList(blenderworld->ipo, converter);
+
+ // For each active channel in the ipoList add an
+ // interpolator to the game object.
+
+ KX_IScalarInterpolator *ipo;
+
+ ipo = ipoList->GetScalarInterpolator(WO_HOR_R);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_mist_rgb[0], ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyMistColor(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(WO_HOR_G);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_mist_rgb[1], ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyMistColor(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(WO_HOR_B);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_mist_rgb[2], ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyMistColor(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(WO_MISTDI);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_mist_dist, ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyMistDist(true);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(WO_MISTSTA);
+ if (ipo) {
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(&ipocontr->m_mist_start, ipo);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyMistStart(true);
+ }
+ }
+}
+
+
+void BL_ConvertMaterialIpos(
+ Material* blendermaterial,
+ KX_GameObject* gameobj,
+ KX_BlenderSceneConverter *converter
+ )
+{
+ if (blendermaterial->ipo) {
+
+ KX_MaterialIpoController* ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+
+ BL_InterpolatorList *ipoList= GetIpoList(blendermaterial->ipo, converter);
+
+
+ ipocontr->m_rgba[0] = blendermaterial->r;
+ ipocontr->m_rgba[1] = blendermaterial->g;
+ ipocontr->m_rgba[2] = blendermaterial->b;
+ ipocontr->m_rgba[3] = blendermaterial->alpha;
+
+ ipocontr->m_specrgb[0] = blendermaterial->specr;
+ ipocontr->m_specrgb[1] = blendermaterial->specg;
+ ipocontr->m_specrgb[2] = blendermaterial->specb;
+
+ ipocontr->m_hard = blendermaterial->har;
+ ipocontr->m_spec = blendermaterial->spec;
+ ipocontr->m_ref = blendermaterial->ref;
+ ipocontr->m_emit = blendermaterial->emit;
+ ipocontr->m_alpha = blendermaterial->alpha;
+ KX_IScalarInterpolator *ipo;
+
+ // --
+ ipo = ipoList->GetScalarInterpolator(MA_COL_R);
+ if (ipo) {
+ if (!ipocontr) {
+ ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_rgba[0],
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(MA_COL_G);
+ if (ipo) {
+ if (!ipocontr) {
+ ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_rgba[1],
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(MA_COL_B);
+ if (ipo) {
+ if (!ipocontr) {
+ ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_rgba[2],
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(MA_ALPHA);
+ if (ipo) {
+ if (!ipocontr) {
+ ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_rgba[3],
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+ // --
+
+ ipo = ipoList->GetScalarInterpolator(MA_SPEC_R );
+ if (ipo) {
+ if (!ipocontr) {
+ ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_specrgb[0],
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(MA_SPEC_G);
+ if (ipo) {
+ if (!ipocontr) {
+ ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_specrgb[1],
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(MA_SPEC_B);
+ if (ipo) {
+ if (!ipocontr) {
+ ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_specrgb[2],
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+
+ // --
+ ipo = ipoList->GetScalarInterpolator(MA_HARD);
+ if (ipo) {
+ if (!ipocontr) {
+ ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_hard,
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(MA_SPEC);
+ if (ipo) {
+ if (!ipocontr) {
+ ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_spec,
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+
+
+ ipo = ipoList->GetScalarInterpolator(MA_REF);
+ if (ipo) {
+ if (!ipocontr) {
+ ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_ref,
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+
+ ipo = ipoList->GetScalarInterpolator(MA_EMIT);
+ if (ipo) {
+ if (!ipocontr) {
+ ipocontr = new KX_MaterialIpoController();
+ gameobj->GetSGNode()->AddSGController(ipocontr);
+ ipocontr->SetObject(gameobj->GetSGNode());
+ }
+ KX_IInterpolator *interpolator =
+ new KX_ScalarInterpolator(
+ &ipocontr->m_emit,
+ ipo);
+ ipocontr->AddInterpolator(interpolator);
+ }
+ }
+}
+
diff --git a/source/gameengine/Converter/KX_IpoConvert.h b/source/gameengine/Converter/KX_IpoConvert.h
new file mode 100644
index 00000000000..e901ae9b3e7
--- /dev/null
+++ b/source/gameengine/Converter/KX_IpoConvert.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 __KX_IPOCONVERT_H
+#define __KX_IPOCONVERT_H
+
+struct Object;
+
+void BL_ConvertIpos(struct Object* blenderobject,
+ class KX_GameObject* gameobj,
+ class KX_BlenderSceneConverter *converter);
+
+void BL_ConvertLampIpos(struct Lamp* blenderlight,
+ class KX_GameObject* lightobj,
+ class KX_BlenderSceneConverter *converter);
+
+void BL_ConvertWorldIpos(struct World* blenderworld,
+ class KX_BlenderSceneConverter *converter);
+
+void BL_ConvertCameraIpos(struct Camera* blendercamera,
+ class KX_GameObject* cameraobj,
+ class KX_BlenderSceneConverter *converter);
+
+void BL_ConvertMaterialIpos(struct Material* blendermaterial,
+ class KX_GameObject* materialobj,
+ class KX_BlenderSceneConverter *converter);
+
+
+#endif //__KX_IPOCONVERT_H
+
diff --git a/source/gameengine/Converter/Makefile b/source/gameengine/Converter/Makefile
new file mode 100644
index 00000000000..4ba34952d40
--- /dev/null
+++ b/source/gameengine/Converter/Makefile
@@ -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 *****
+#
+#
+
+LIBNAME = blconverter
+DIR = $(OCGDIR)/gameengine/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO) -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_SOLID)/include
+CPPFLAGS += -I$(NAN_BULLET2)/include
+
+CPPFLAGS += -I../../blender
+# these two needed because of blenkernel
+CPPFLAGS += -I../../blender/imbuf
+CPPFLAGS += -I../../blender/makesdna
+CPPFLAGS += -I../../blender/include
+CPPFLAGS += -I../../blender/blenlib
+CPPFLAGS += -I../../blender/blenkernel
+CPPFLAGS += -I../../blender/render/extern/include
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../Expressions -I../Rasterizer -I../GameLogic
+CPPFLAGS += -I../Ketsji -I../BlenderRoutines -I../SceneGraph
+CPPFLAGS += -I../../kernel/gen_system
+CPPFLAGS += -I../Rasterizer/RAS_OpenGLRasterizer
+CPPFLAGS += -I../Network -I../Ketsji/KXNetwork
+CPPFLAGS += -I../Physics/common -I../Physics/Dummy
+CPPFLAGS += -I../Physics/BlOde
+CPPFLAGS += -I../Physics/Bullet
+CPPFLAGS += -I.
diff --git a/source/gameengine/Converter/SConscript b/source/gameengine/Converter/SConscript
new file mode 100644
index 00000000000..f5e382b471e
--- /dev/null
+++ b/source/gameengine/Converter/SConscript
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('*.cpp')
+
+incs = '. #source/kernel/gen_system #intern/string #intern/guardedalloc'
+incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #intern/bmfont'
+incs += ' #intern/SoundSystem #intern/SoundSystem/include #intern/SoundSystem/openal'
+incs += ' #intern/SoundSystem/dummy #intern/SoundSystem/intern #source/gameengine/Converter'
+incs += ' #source/gameengine/BlenderRoutines #source/blender/imbuf'
+incs += ' #intern/moto/include #source/gameengine/Ketsji #source/gameengine/Ketsji/KXNetwork'
+incs += ' #source/blender/blenlib #source/blender/blenkernel #source/blender'
+incs += ' #source/blender/include #source/blender/makesdna #source/gameengine/Rasterizer'
+incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #source/gameengine/GameLogic'
+incs += ' #source/gameengine/Expressions #source/gameengine/Network #source/gameengine/SceneGraph'
+incs += ' #source/gameengine/Physics/common #source/gameengine/Physics/Bullet #source/gameengine/Physics/BlOde'
+incs += ' #source/gameengine/Physics/Dummy #source/gameengine/Physics/Sumo'
+incs += ' #source/gameengine/Physics/Sumo/Fuzzics/include #source/gameengine/Network/LoopBackNetwork'
+incs += ' #source/blender/misc #source/blender/blenloader'
+
+incs += ' ' + env['BF_PYTHON_INC']
+incs += ' ' + env['BF_SOLID_INC']
+incs += ' ' + env['BF_BULLET_INC']
+
+env.BlenderLib ( 'bf_converter', sources, Split(incs), [], libtype=['game','player'], priority=[5,70] )
diff --git a/source/gameengine/Expressions/BoolValue.cpp b/source/gameengine/Expressions/BoolValue.cpp
new file mode 100644
index 00000000000..cadb34d7e8f
--- /dev/null
+++ b/source/gameengine/Expressions/BoolValue.cpp
@@ -0,0 +1,214 @@
+
+// BoolValue.cpp: implementation of the CBoolValue class.
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#include "BoolValue.h"
+#include "StringValue.h"
+#include "ErrorValue.h"
+#include "VoidValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+
+CBoolValue::CBoolValue()
+/*
+pre: false
+effect: constructs a new CBoolValue
+*/
+{
+ trace("Bool constructor error");
+}
+
+
+
+CBoolValue::CBoolValue(bool inBool)
+: m_bool(inBool)
+{
+} // Constructs a new CBoolValue containing <inBool>
+
+
+
+CBoolValue::CBoolValue(bool innie,STR_String name,AllocationTYPE alloctype)
+{
+ m_bool = innie;
+ SetName(name);
+
+ if (alloctype == CValue::STACKVALUE)
+ CValue::DisableRefCount();
+}
+
+
+
+void CBoolValue::SetValue(CValue* newval)
+{
+ m_bool = (newval->GetNumber() != 0);
+ SetModified(true);
+}
+
+
+
+CValue* CBoolValue::Calc(VALUE_OPERATOR op, CValue *val)
+/*
+pre:
+ret: a new object containing the result of applying operator op to this
+object and val
+*/
+{
+ switch (op)
+ {
+ case VALUE_POS_OPERATOR:
+ case VALUE_NEG_OPERATOR:
+ {
+ return new CErrorValue (op2str(op) + GetText());
+ break;
+ }
+ case VALUE_NOT_OPERATOR:
+ {
+ return new CBoolValue (!m_bool);
+ break;
+ }
+ default:
+ {
+ return val->CalcFinal(VALUE_BOOL_TYPE, op, this);
+ break;
+ }
+ }
+}
+
+
+
+CValue* CBoolValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val)
+/*
+pre: the type of val is dtype
+ret: a new object containing the result of applying operator op to val and
+this object
+*/
+{
+ CValue *ret;
+
+ switch(dtype)
+ {
+ case VALUE_EMPTY_TYPE:
+ case VALUE_BOOL_TYPE:
+ {
+ switch(op)
+ {
+ case VALUE_AND_OPERATOR:
+ {
+ ret = new CBoolValue (((CBoolValue *) val)->GetBool() && m_bool);
+ break;
+ }
+ case VALUE_OR_OPERATOR:
+ {
+ ret = new CBoolValue (((CBoolValue *) val)->GetBool() || m_bool);
+ break;
+ }
+ case VALUE_EQL_OPERATOR:
+ {
+ ret = new CBoolValue (((CBoolValue *) val)->GetBool() == m_bool);
+ break;
+ }
+ case VALUE_NEQ_OPERATOR:
+ {
+ ret = new CBoolValue (((CBoolValue *) val)->GetBool() != m_bool);
+ break;
+ }
+ case VALUE_NOT_OPERATOR:
+ {
+ return new CBoolValue (!m_bool);
+ break;
+ }
+ default:
+ {
+ ret = new CErrorValue(val->GetText() + op2str(op) +
+ "[operator not allowed on booleans]");
+ break;
+ }
+ }
+ break;
+ }
+ case VALUE_STRING_TYPE:
+ {
+ switch(op)
+ {
+ case VALUE_ADD_OPERATOR:
+ {
+ ret = new CStringValue(val->GetText() + GetText(),"");
+ break;
+ }
+ default:
+ {
+ ret = new CErrorValue(val->GetText() + op2str(op) + "[Only + allowed on boolean and string]");
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ ret = new CErrorValue("[type mismatch]" + op2str(op) + GetText());
+ }
+
+ return ret;
+}
+
+
+
+bool CBoolValue::GetBool()
+/*
+pre:
+ret: the bool stored in the object
+*/
+{
+ return m_bool;
+}
+
+
+
+float CBoolValue::GetNumber()
+{
+ return (float)m_bool;
+}
+
+
+
+const STR_String& CBoolValue::GetText()
+{
+ static STR_String sTrueString = STR_String("TRUE");
+ static STR_String sFalseString = STR_String("FALSE");
+
+ return m_bool ? sTrueString : sFalseString;
+}
+
+
+
+CValue* CBoolValue::GetReplica()
+{
+ CBoolValue* replica = new CBoolValue(*this);
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+PyObject* CBoolValue::ConvertValueToPython()
+{
+ return PyInt_FromLong(m_bool != 0);
+}
diff --git a/source/gameengine/Expressions/BoolValue.h b/source/gameengine/Expressions/BoolValue.h
new file mode 100644
index 00000000000..6c4d964249f
--- /dev/null
+++ b/source/gameengine/Expressions/BoolValue.h
@@ -0,0 +1,52 @@
+/*
+ * BoolValue.h: interface for the CBoolValue class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#if !defined _BOOLVALUE_H
+#define _BOOLVALUE_H
+
+#include "Value.h"
+
+/**
+ * Smart Boolean Value class.
+ * Is used by parser when an expression tree is build containing booleans.
+ */
+
+class CBoolValue : public CPropValue
+{
+
+ //PLUGIN_DECLARE_SERIAL(CBoolValue,CValue)
+
+public:
+ CBoolValue();
+ CBoolValue(bool inBool);
+ CBoolValue(bool innie, STR_String name, AllocationTYPE alloctype = CValue::HEAPVALUE);
+
+ virtual const STR_String& GetText();
+ virtual float GetNumber();
+ bool GetBool();
+ virtual void SetValue(CValue* newval);
+
+ virtual CValue* Calc(VALUE_OPERATOR op, CValue *val);
+ virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+
+ void Configure(CValue* menuvalue);
+ virtual CValue* GetReplica();
+ virtual PyObject* ConvertValueToPython();
+
+private:
+ bool m_bool;
+};
+
+#endif // !defined _BOOLVALUE_H
+
diff --git a/source/gameengine/Expressions/CMakeLists.txt b/source/gameengine/Expressions/CMakeLists.txt
new file mode 100644
index 00000000000..cc99be1b9ee
--- /dev/null
+++ b/source/gameengine/Expressions/CMakeLists.txt
@@ -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) 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 *.cpp)
+
+SET(INC
+ .
+ ../../../source/kernel/gen_system
+ ../../../intern/string
+ ../../../intern/moto/include
+ ${PYTHON_INC}
+)
+
+BLENDERLIB(bf_expressions "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_expressions', sources, Split(incs), [], libtype=['game','player'], priority = [45,125] )
diff --git a/source/gameengine/Expressions/ConstExpr.cpp b/source/gameengine/Expressions/ConstExpr.cpp
new file mode 100644
index 00000000000..e33ba091ac4
--- /dev/null
+++ b/source/gameengine/Expressions/ConstExpr.cpp
@@ -0,0 +1,132 @@
+// ConstExpr.cpp: implementation of the CConstExpr class.
+
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#include "Value.h" // for precompiled header
+#include "ConstExpr.h"
+#include "VectorValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CConstExpr::CConstExpr()
+{
+}
+
+
+
+CConstExpr::CConstExpr(CValue* constval)
+/*
+pre:
+effect: constructs a CConstExpr cointing the value constval
+*/
+{
+ m_value = constval;
+// m_bModified=true;
+}
+
+
+
+CConstExpr::~CConstExpr()
+/*
+pre:
+effect: deletes the object
+*/
+{
+ if (m_value)
+ m_value->Release();
+}
+
+
+
+unsigned char CConstExpr::GetExpressionID()
+{
+ return CCONSTEXPRESSIONID;
+}
+
+
+
+CValue* CConstExpr::Calculate()
+/*
+pre:
+ret: a new object containing the value of the stored CValue
+*/
+{
+ return m_value->AddRef();
+}
+
+
+
+void CConstExpr::ClearModified()
+{
+ if (m_value)
+ {
+ m_value->SetModified(false);
+ m_value->SetAffected(false);
+ }
+}
+
+
+
+float CConstExpr::GetNumber()
+{
+ return -1;
+}
+
+
+
+bool CConstExpr::NeedsRecalculated()
+{
+ return m_value->IsAffected(); // IsAffected is m_bModified OR m_bAffected !!!
+}
+
+
+
+CExpression* CConstExpr::CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks)
+{
+// parent checks if child is still usefull.
+// When for example it's value it's deleted flag set
+// then release Value, and return NULL in case of constexpression
+// else return this...
+
+ assertd(m_value);
+ if (m_value->IsReleaseRequested())
+ {
+ AddRef(); //numchanges++;
+ return Release();
+ }
+ else
+ return this;
+}
+
+
+
+void CConstExpr::BroadcastOperators(VALUE_OPERATOR op)
+{
+ assertd(m_value);
+ m_value->SetColorOperator(op);
+}
+
+
+
+bool CConstExpr::MergeExpression(CExpression *otherexpr)
+{
+ assertd(false);
+ return false;
+}
diff --git a/source/gameengine/Expressions/ConstExpr.h b/source/gameengine/Expressions/ConstExpr.h
new file mode 100644
index 00000000000..e27ece52a83
--- /dev/null
+++ b/source/gameengine/Expressions/ConstExpr.h
@@ -0,0 +1,47 @@
+/*
+ * ConstExpr.h: interface for the CConstExpr class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifndef __CONSTEXPR_H__
+#define __CONSTEXPR_H__
+
+#include "Expression.h"
+#include "Value.h" // Added by ClassView
+
+class CConstExpr : public CExpression
+{
+ //PLUGIN_DECLARE_SERIAL_EXPRESSION (CConstExpr,CExpression)
+public:
+ virtual bool MergeExpression(CExpression* otherexpr);
+
+ void BroadcastOperators(VALUE_OPERATOR op);
+
+ virtual unsigned char GetExpressionID();
+ CExpression* CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks);
+ //bool IsInside(float x,float y,float z,bool bBorderInclude=true);
+ bool NeedsRecalculated();
+ void ClearModified();
+ virtual float GetNumber();
+ virtual CValue* Calculate();
+ CConstExpr(CValue* constval);
+ CConstExpr();
+ virtual ~CConstExpr();
+
+
+private:
+ CValue* m_value;
+};
+
+#endif // !defined(AFX_CONSTEXPR_H__061ECFC3_BE87_11D1_A51C_00A02472FC58__INCLUDED_)
+
diff --git a/source/gameengine/Expressions/EXP_C-Api.cpp b/source/gameengine/Expressions/EXP_C-Api.cpp
new file mode 100644
index 00000000000..c5576e99e7d
--- /dev/null
+++ b/source/gameengine/Expressions/EXP_C-Api.cpp
@@ -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 *****
+ */
+#include "EXP_C-Api.h"
+#include "IntValue.h"
+#include "BoolValue.h"
+#include "StringValue.h"
+#include "ErrorValue.h"
+#include "InputParser.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+EXP_ValueHandle EXP_CreateInt(int innie)
+{
+ return (EXP_ValueHandle) new CIntValue(innie);
+}
+
+
+
+EXP_ValueHandle EXP_CreateBool(int innie)
+{
+ return (EXP_ValueHandle) new CBoolValue(innie!=0);
+}
+
+
+
+EXP_ValueHandle EXP_CreateString(const char* str)
+{
+
+ return (EXP_ValueHandle) new CStringValue(str,"");
+}
+
+
+
+void EXP_SetName(EXP_ValueHandle inval,const char* newname)
+{
+ ((CValue*) inval)->SetName(newname);
+}
+
+
+
+/* calculate expression from inputtext */
+EXP_ValueHandle EXP_ParseInput(const char* inputtext)
+{
+ CValue* resultval=NULL;
+ CParser parser;
+ CExpression* expr = parser.ProcessText(inputtext);
+ if (expr)
+ {
+ resultval = expr->Calculate();
+ expr->Release();
+ }
+ else
+ {
+ resultval = new CErrorValue("couldn't parsetext");
+ }
+
+ return (EXP_ValueHandle) resultval;
+}
+
+
+
+void EXP_ReleaseValue(EXP_ValueHandle inval)
+{
+ ((CValue*) inval)->Release();
+}
+
+
+
+int EXP_IsValid(EXP_ValueHandle inval)
+{
+ return !((CValue*) inval)->IsError();
+}
+
+
+
+/* assign property 'propval' to 'destinationval' */
+void EXP_SetProperty(EXP_ValueHandle destinationval,
+ const char* propname,
+ EXP_ValueHandle propval)
+{
+ ((CValue*) destinationval)->SetProperty(propname,(CValue*)propval);
+}
+
+
+
+const char* EXP_GetText(EXP_ValueHandle inval)
+{
+ return ((CValue*) inval)->GetText();
+}
+
+
+
+EXP_ValueHandle EXP_GetProperty(EXP_ValueHandle inval,const char* propname)
+{
+ return (EXP_ValueHandle) ((CValue*)inval)->GetProperty(propname);
+}
diff --git a/source/gameengine/Expressions/EXP_C-Api.h b/source/gameengine/Expressions/EXP_C-Api.h
new file mode 100644
index 00000000000..e9ee526cd6e
--- /dev/null
+++ b/source/gameengine/Expressions/EXP_C-Api.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef __EXPRESSION_INCLUDE
+#define __EXPRESSION_INCLUDE
+
+#define EXP_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
+
+EXP_DECLARE_HANDLE(EXP_ValueHandle);
+EXP_DECLARE_HANDLE(EXP_ExpressionHandle);
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern EXP_ValueHandle EXP_CreateInt(int innie);
+extern EXP_ValueHandle EXP_CreateBool(int innie);
+extern EXP_ValueHandle EXP_CreateString(const char* str);
+extern void EXP_SetName(EXP_ValueHandle,const char* newname);
+
+/* calculate expression from inputtext */
+extern EXP_ValueHandle EXP_ParseInput(const char* inputtext);
+extern void EXP_ReleaseValue(EXP_ValueHandle);
+extern int EXP_IsValid(EXP_ValueHandle);
+
+/* assign property 'propval' to 'destinationval' */
+extern void EXP_SetProperty(EXP_ValueHandle propval,EXP_ValueHandle destinationval);
+
+/* returns NULL if property doesn't exist */
+extern EXP_ValueHandle EXP_GetProperty(EXP_ValueHandle inval,const char* propname);
+
+const char* EXP_GetText(EXP_ValueHandle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__EXPRESSION_INCLUDE
+
diff --git a/source/gameengine/Expressions/EmptyValue.cpp b/source/gameengine/Expressions/EmptyValue.cpp
new file mode 100644
index 00000000000..c2b60e590a4
--- /dev/null
+++ b/source/gameengine/Expressions/EmptyValue.cpp
@@ -0,0 +1,127 @@
+
+// EmptyValue.cpp: implementation of the CEmptyValue class.
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#include "EmptyValue.h"
+#include "IntValue.h"
+#include "FloatValue.h"
+#include "StringValue.h"
+#include "ErrorValue.h"
+#include "ListValue.h"
+#include "VoidValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CEmptyValue::CEmptyValue()
+/*
+pre:
+effect: constructs a new CEmptyValue
+*/
+{
+ SetModified(false);
+}
+
+
+
+CEmptyValue::~CEmptyValue()
+/*
+pre:
+effect: deletes the object
+*/
+{
+
+}
+
+
+
+CValue * CEmptyValue::Calc(VALUE_OPERATOR op, CValue * val)
+/*
+pre:
+ret: a new object containing the result of applying operator op to this
+object and val
+*/
+{
+ return val->CalcFinal(VALUE_EMPTY_TYPE, op, this);
+
+}
+
+
+
+CValue * CEmptyValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue * val)
+/*
+pre: the type of val is dtype
+ret: a new object containing the result of applying operator op to val and
+this object
+*/
+{
+ return val->AddRef();
+}
+
+
+
+float CEmptyValue::GetNumber()
+{
+ return 0;
+}
+
+
+
+CListValue* CEmptyValue::GetPolySoup()
+{
+ CListValue* soup = new CListValue();
+ //don't add any poly, while it's an empty value
+ return soup;
+}
+
+
+
+bool CEmptyValue::IsInside(CValue* testpoint,bool bBorderInclude)
+{
+ // empty space is solid, so always inside
+ return true;
+}
+
+
+
+double* CEmptyValue::GetVector3(bool bGetTransformedVec)
+{
+ assertd(false); // don't get vector from me
+ return ZeroVector();
+}
+
+
+
+static STR_String emptyString = STR_String("");
+
+
+const STR_String & CEmptyValue::GetText()
+{
+ return emptyString;
+}
+
+
+
+CValue* CEmptyValue::GetReplica()
+{
+ CEmptyValue* replica = new CEmptyValue(*this);
+ CValue::AddDataToReplica(replica);
+ return replica;
+}
+
diff --git a/source/gameengine/Expressions/EmptyValue.h b/source/gameengine/Expressions/EmptyValue.h
new file mode 100644
index 00000000000..b9cca0e57e5
--- /dev/null
+++ b/source/gameengine/Expressions/EmptyValue.h
@@ -0,0 +1,40 @@
+/*
+ * EmptyValue.h: interface for the CEmptyValue class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#if !defined _EMPTYVALUE_H
+#define _EMPTYVALUE_H
+
+#include "Value.h"
+
+class CListValue;
+
+class CEmptyValue : public CPropValue
+{
+ //PLUGIN_DECLARE_SERIAL (CEmptyValue,CValue)
+public:
+ CEmptyValue();
+ virtual ~CEmptyValue();
+
+ virtual const STR_String & GetText();
+ virtual float GetNumber();
+ CListValue* GetPolySoup();
+ virtual double* GetVector3(bool bGetTransformedVec=false);
+ bool IsInside(CValue* testpoint,bool bBorderInclude=true);
+ CValue * Calc(VALUE_OPERATOR op, CValue *val);
+ CValue * CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+ virtual CValue* GetReplica();
+};
+
+#endif // !defined _EMPTYVALUE_H
+
diff --git a/source/gameengine/Expressions/ErrorValue.cpp b/source/gameengine/Expressions/ErrorValue.cpp
new file mode 100644
index 00000000000..e52be4c8021
--- /dev/null
+++ b/source/gameengine/Expressions/ErrorValue.cpp
@@ -0,0 +1,123 @@
+// ErrorValue.cpp: implementation of the CErrorValue class.
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#include "ErrorValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CErrorValue::CErrorValue()
+/*
+pre:
+effect: constructs a new CErrorValue containing errormessage "Error"
+*/
+{
+ m_strErrorText = "Error";
+ SetError(true);
+}
+
+
+
+CErrorValue::CErrorValue(STR_String errmsg)
+/*
+pre:
+effect: constructs a new CErrorValue containing errormessage errmsg
+*/
+{
+ m_strErrorText = "[" + errmsg + "]";
+ SetError(true);
+}
+
+
+
+CErrorValue::~CErrorValue()
+/*
+pre:
+effect: deletes the object
+*/
+{
+
+}
+
+
+
+CValue* CErrorValue::Calc(VALUE_OPERATOR op, CValue *val)
+/*
+pre:
+ret: a new object containing the result of applying operator op to this
+ object and val
+*/
+{
+ CValue* errorval;
+
+ switch (op)
+ {
+ case VALUE_POS_OPERATOR:
+ case VALUE_NEG_OPERATOR:
+ case VALUE_NOT_OPERATOR:
+ {
+ errorval = new CErrorValue (op2str(op) + GetText());
+ break;
+ }
+ default:
+ {
+ errorval = val->CalcFinal(VALUE_ERROR_TYPE, op, this);
+ break;
+ }
+ }
+
+ return errorval;
+}
+
+
+
+CValue* CErrorValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val)
+/*
+pre: the type of val is dtype
+ret: a new object containing the result of applying operator op to val and
+ this object
+*/
+{
+ return new CErrorValue (val->GetText() + op2str(op) + GetText());
+}
+
+
+
+float CErrorValue::GetNumber()
+{
+ return -1;
+}
+
+
+
+const STR_String & CErrorValue::GetText()
+{
+ return m_strErrorText;
+}
+
+
+
+CValue* CErrorValue::GetReplica()
+{
+ // who would want a copy of an error ?
+ trace ("Error: ErrorValue::GetReplica() not implemented yet");
+ assertd(false);
+
+ return NULL;
+}
diff --git a/source/gameengine/Expressions/ErrorValue.h b/source/gameengine/Expressions/ErrorValue.h
new file mode 100644
index 00000000000..16e608ca01a
--- /dev/null
+++ b/source/gameengine/Expressions/ErrorValue.h
@@ -0,0 +1,39 @@
+/*
+ * ErrorValue.h: interface for the CErrorValue class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#if !defined _ERRORVALUE_H
+#define _ERRORVALUE_H
+
+#include "Value.h"
+
+class CErrorValue : public CPropValue
+{
+
+public:
+ virtual const STR_String & GetText();
+ virtual float GetNumber();
+ CErrorValue();
+ CErrorValue(STR_String errmsg);
+ virtual ~CErrorValue();
+ virtual CValue* Calc(VALUE_OPERATOR op, CValue* val);
+ virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+ virtual CValue* GetReplica();
+
+private:
+ STR_String m_strErrorText;
+};
+
+#endif // !defined _ERRORVALUE_H
+
diff --git a/source/gameengine/Expressions/Expression.cpp b/source/gameengine/Expressions/Expression.cpp
new file mode 100644
index 00000000000..5c5e1abea34
--- /dev/null
+++ b/source/gameengine/Expressions/Expression.cpp
@@ -0,0 +1,76 @@
+// Expression.cpp: implementation of the CExpression class.
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#include "Expression.h"
+#include "ErrorValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CExpression::CExpression()// : m_cached_calculate(NULL)
+{
+ m_refcount = 1;
+#ifdef _DEBUG
+ //gRefCountExpr++;
+#endif
+}
+
+CExpression::~CExpression()
+{
+ assert (m_refcount == 0);
+}
+
+
+
+// destuctor for CBrokenLinkInfo
+CBrokenLinkInfo::~CBrokenLinkInfo()
+{
+ if (m_pExpr && !m_bRestored)
+ m_pExpr->Release();
+}
+
+
+void CBrokenLinkInfo::RestoreLink()
+{
+
+
+ assertd(m_pExpr);
+
+ if (m_pExpr)
+ {
+ if (!m_bRestored){
+ m_bRestored=true;
+
+ }
+ if (*m_pmemExpr)
+ {
+ (*m_pmemExpr)->Release();
+ }
+ *m_pmemExpr = m_pExpr;
+
+// m_pExpr=NULL;
+ }
+}
+
+void CBrokenLinkInfo::BreakLink()
+{
+ m_bRestored=false;
+ m_pExpr->AddRef();
+}
+
diff --git a/source/gameengine/Expressions/Expression.h b/source/gameengine/Expressions/Expression.h
new file mode 100644
index 00000000000..400a2b7c789
--- /dev/null
+++ b/source/gameengine/Expressions/Expression.h
@@ -0,0 +1,132 @@
+/*
+ * Expression.h: interface for the CExpression class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#if !defined _EXPRESSION_H
+#define _EXPRESSION_H
+
+#include "Value.h"
+
+//extern int gRefCountExpr; // only for debugging purposes (detect mem.leaks)
+
+
+#define PLUGIN_DECLARE_SERIAL_EXPRESSION(class_name,base_class_name) \
+public: \
+ virtual base_class_name * Copy() { return new class_name; } \
+ virtual bool EdSerialize(CompressorArchive& arch,class CFactoryManager* facmgr,bool bIsStoring); \
+ virtual bool EdIdSerialize(CompressorArchive& arch,class CFactoryManager* facmgr,bool bIsStoring) \
+{ \
+ if (bIsStoring) \
+ { \
+ unsigned char exprID = GetExpressionID(); \
+ arch << exprID; \
+ } \
+ return true; \
+} \
+
+
+
+class CExpression;
+
+
+// for undo/redo system the deletion in the expressiontree can be restored by replacing broken links 'inplace'
+class CBrokenLinkInfo
+{
+ public:
+ CBrokenLinkInfo(CExpression** pmemexpr,CExpression* expr)
+ :m_pmemExpr(pmemexpr),
+ m_pExpr(expr)
+ {
+ assertd(pmemexpr);
+ m_bRestored=false;
+ };
+
+ virtual ~CBrokenLinkInfo();
+ void RestoreLink();
+ void BreakLink();
+
+
+ // members vars
+ private:
+ CExpression** m_pmemExpr;
+ CExpression* m_pExpr;
+ bool m_bRestored;
+
+};
+
+
+
+
+
+
+
+
+class CExpression
+{
+public:
+ enum {
+ COPERATOR1EXPRESSIONID = 1,
+ COPERATOR2EXPRESSIONID = 2,
+ CCONSTEXPRESSIONID = 3,
+ CIFEXPRESSIONID = 4,
+ COPERATORVAREXPRESSIONID = 5,
+ CIDENTIFIEREXPRESSIONID = 6
+ };
+
+
+protected:
+ virtual ~CExpression() = 0; //pure virtual
+public:
+ virtual bool MergeExpression(CExpression* otherexpr) = 0;
+ CExpression();
+
+
+ virtual CValue* Calculate() = 0; //pure virtual
+ virtual unsigned char GetExpressionID() = 0;
+ //virtual bool IsInside(float x,float y,float z,bool bBorderInclude=true) = 0; //pure virtual
+ virtual bool NeedsRecalculated() = 0; // another pure one
+ virtual CExpression * CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks) =0; // another pure one
+ virtual void ClearModified() = 0; // another pure one
+ //virtual CExpression * Copy() =0;
+ virtual void BroadcastOperators(VALUE_OPERATOR op) =0;
+
+ virtual CExpression * AddRef() { // please leave multiline, for debugger !!!
+
+#ifdef _DEBUG
+ //gRefCountExpr++;
+ assertd(m_refcount < 255);
+#endif
+ m_refcount++;
+ return this;
+ };
+ virtual CExpression* Release(CExpression* complicatedtrick=NULL) {
+#ifdef _DEBUG
+ //gRefCountExpr--;
+#endif
+ if (--m_refcount < 1)
+ {
+ delete this;
+ } //else
+ // return this;
+ return complicatedtrick;
+ };
+
+
+protected:
+
+ int m_refcount;
+};
+
+#endif // !defined _EXPRESSION_H
+
diff --git a/source/gameengine/Expressions/FloatValue.cpp b/source/gameengine/Expressions/FloatValue.cpp
new file mode 100644
index 00000000000..93f102d04a6
--- /dev/null
+++ b/source/gameengine/Expressions/FloatValue.cpp
@@ -0,0 +1,316 @@
+// FloatValue.cpp: implementation of the CFloatValue class.
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#include "FloatValue.h"
+#include "IntValue.h"
+#include "StringValue.h"
+#include "BoolValue.h"
+#include "ErrorValue.h"
+#include "VoidValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CFloatValue::CFloatValue()
+/*
+pre: false
+effect: constructs a new CFloatValue
+*/
+{
+ m_pstrRep=NULL;
+}
+
+
+
+CFloatValue::CFloatValue(float fl)
+/*
+pre:
+effect: constructs a new CFloatValue containing value fl
+*/
+{
+ m_float = fl;
+ m_pstrRep=NULL;
+}
+
+
+
+CFloatValue::CFloatValue(float fl,STR_String name,AllocationTYPE alloctype)
+/*
+pre:
+effect: constructs a new CFloatValue containing value fl
+*/
+{
+
+ m_float = fl;
+ SetName(name);
+ if (alloctype==CValue::STACKVALUE)
+ {
+ CValue::DisableRefCount();
+
+ }
+ m_pstrRep=NULL;
+}
+
+
+
+CFloatValue::~CFloatValue()
+/*
+pre:
+effect: deletes the object
+*/
+{
+ if (m_pstrRep)
+ delete m_pstrRep;
+}
+
+
+
+CValue* CFloatValue::Calc(VALUE_OPERATOR op, CValue *val)
+/*
+pre:
+ret: a new object containing the result of applying operator op to this
+ object and val
+*/
+{
+ //return val->CalcFloat(op, this);
+ switch (op)
+ {
+ case VALUE_POS_OPERATOR:
+ return new CFloatValue (m_float);
+ break;
+ case VALUE_NEG_OPERATOR:
+ return new CFloatValue (-m_float);
+ break;
+ case VALUE_NOT_OPERATOR:
+ return new CErrorValue (op2str(op) + "only allowed on booleans");
+ break;
+ case VALUE_AND_OPERATOR:
+ case VALUE_OR_OPERATOR:
+ return new CErrorValue(val->GetText() + op2str(op) + "only allowed on booleans");
+ break;
+ default:
+ return val->CalcFinal(VALUE_FLOAT_TYPE, op, this);
+ break;
+ }
+}
+
+
+
+CValue* CFloatValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val)
+/*
+pre: the type of val is dtype
+ret: a new object containing the result of applying operator op to val and
+ this object
+*/
+{
+ CValue *ret;
+
+ switch(dtype)
+ {
+ case VALUE_INT_TYPE:
+ {
+ switch (op)
+ {
+ case VALUE_ADD_OPERATOR:
+ ret = new CFloatValue(((CIntValue *) val)->GetInt() + m_float);
+ break;
+ case VALUE_SUB_OPERATOR:
+ ret = new CFloatValue(((CIntValue *) val)->GetInt() - m_float);
+ break;
+ case VALUE_MUL_OPERATOR:
+ ret = new CFloatValue(((CIntValue *) val)->GetInt() * m_float);
+ break;
+ case VALUE_DIV_OPERATOR:
+ if (m_float == 0)
+ ret = new CErrorValue("Division by zero");
+ else
+ ret = new CFloatValue (((CIntValue *) val)->GetInt() / m_float);
+ break;
+ case VALUE_EQL_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() == m_float);
+ break;
+ case VALUE_NEQ_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() != m_float);
+ break;
+ case VALUE_GRE_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() > m_float);
+ break;
+ case VALUE_LES_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() < m_float);
+ break;
+ case VALUE_GEQ_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() >= m_float);
+ break;
+ case VALUE_LEQ_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() <= m_float);
+ break;
+ default:
+ ret = new CErrorValue("illegal operator. please send a bug report.");
+ break;
+ }
+ break;
+ }
+ case VALUE_EMPTY_TYPE:
+ case VALUE_FLOAT_TYPE:
+ {
+ switch (op)
+ {
+ case VALUE_ADD_OPERATOR:
+ ret = new CFloatValue(((CFloatValue *) val)->GetFloat() + m_float);
+ break;
+ case VALUE_SUB_OPERATOR:
+ ret = new CFloatValue(((CFloatValue *) val)->GetFloat() - m_float);
+ break;
+ case VALUE_MUL_OPERATOR:
+ ret = new CFloatValue(((CFloatValue *) val)->GetFloat() * m_float);
+ break;
+ case VALUE_DIV_OPERATOR:
+ if (m_float == 0)
+ ret = new CErrorValue("Division by zero");
+ else
+ ret = new CFloatValue (((CFloatValue *) val)->GetFloat() / m_float);
+ break;
+ case VALUE_EQL_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() == m_float);
+ break;
+ case VALUE_NEQ_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() != m_float);
+ break;
+ case VALUE_GRE_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() > m_float);
+ break;
+ case VALUE_LES_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() < m_float);
+ break;
+ case VALUE_GEQ_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() >= m_float);
+ break;
+ case VALUE_LEQ_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() <= m_float);
+ break;
+ case VALUE_NEG_OPERATOR:
+ ret = new CFloatValue (-m_float);
+ break;
+ case VALUE_POS_OPERATOR:
+ ret = new CFloatValue (m_float);
+ break;
+
+ default:
+ ret = new CErrorValue("illegal operator. please send a bug report.");
+ break;
+ }
+ break;
+ }
+ case VALUE_STRING_TYPE:
+ {
+ switch(op)
+ {
+ case VALUE_ADD_OPERATOR:
+ ret = new CStringValue(val->GetText() + GetText(),"");
+ break;
+ case VALUE_EQL_OPERATOR:
+ case VALUE_NEQ_OPERATOR:
+ case VALUE_GRE_OPERATOR:
+ case VALUE_LES_OPERATOR:
+ case VALUE_GEQ_OPERATOR:
+ case VALUE_LEQ_OPERATOR:
+ ret = new CErrorValue("[Cannot compare string with float]" + op2str(op) + GetText());
+ break;
+ default:
+ ret = new CErrorValue("[operator not allowed on strings]" + op2str(op) + GetText());
+ break;
+ }
+ break;
+ }
+ case VALUE_BOOL_TYPE:
+ ret = new CErrorValue("[operator not valid on boolean and float]" + op2str(op) + GetText());
+ break;
+ case VALUE_ERROR_TYPE:
+ ret = new CErrorValue(val->GetText() + op2str(op) + GetText());
+ break;
+ default:
+ ret = new CErrorValue("illegal type. contact your dealer (if any)");
+ break;
+ }
+ return ret;
+}
+
+
+
+void CFloatValue::SetFloat(float fl)
+{
+ m_float = fl;
+ SetModified(true);
+}
+
+
+
+float CFloatValue::GetFloat()
+/*
+pre:
+ret: the float stored in the object
+*/
+{
+ return m_float;
+}
+
+
+
+float CFloatValue::GetNumber()
+{
+ return m_float;
+}
+
+
+
+void CFloatValue::SetValue(CValue* newval)
+{
+ m_float = newval->GetNumber();
+ SetModified(true);
+}
+
+
+
+const STR_String & CFloatValue::GetText()
+{
+ if (!m_pstrRep)
+ m_pstrRep = new STR_String();
+
+ m_pstrRep->Format("%f",m_float);
+ return *m_pstrRep;
+}
+
+
+
+CValue* CFloatValue::GetReplica()
+{
+ CFloatValue* replica = new CFloatValue(*this);
+ replica->m_pstrRep = NULL;
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+PyObject* CFloatValue::ConvertValueToPython()
+{
+ return PyFloat_FromDouble(m_float);
+}
+
diff --git a/source/gameengine/Expressions/FloatValue.h b/source/gameengine/Expressions/FloatValue.h
new file mode 100644
index 00000000000..33f05f1d7f2
--- /dev/null
+++ b/source/gameengine/Expressions/FloatValue.h
@@ -0,0 +1,48 @@
+/*
+ * FloatValue.h: interface for the CFloatValue class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#if !defined _FLOATVALUE_H
+#define _FLOATVALUE_H
+
+#include "Value.h"
+
+class CFloatValue : public CPropValue
+{
+ //PLUGIN_DECLARE_SERIAL (CFloatValue,CValue)
+public:
+ CFloatValue();
+ CFloatValue(float fl);
+ CFloatValue(float fl,STR_String name,AllocationTYPE alloctype=CValue::HEAPVALUE);
+
+ virtual const STR_String & GetText();
+
+ void Configure(CValue* menuvalue);
+ virtual float GetNumber();
+ virtual void SetValue(CValue* newval);
+ float GetFloat();
+ void SetFloat(float fl);
+ virtual ~CFloatValue();
+ virtual CValue* GetReplica();
+ virtual CValue* Calc(VALUE_OPERATOR op, CValue *val);
+ virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+ virtual PyObject* ConvertValueToPython();
+
+protected:
+ float m_float;
+ STR_String* m_pstrRep;
+
+};
+
+#endif // !defined _FLOATVALUE_H
+
diff --git a/source/gameengine/Expressions/IdentifierExpr.cpp b/source/gameengine/Expressions/IdentifierExpr.cpp
new file mode 100644
index 00000000000..cd7a9b0f186
--- /dev/null
+++ b/source/gameengine/Expressions/IdentifierExpr.cpp
@@ -0,0 +1,106 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "IdentifierExpr.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+CIdentifierExpr::CIdentifierExpr(const STR_String& identifier,CValue* id_context)
+:m_identifier(identifier)
+{
+ if (id_context)
+ m_idContext = id_context->AddRef();
+ else
+ m_idContext=NULL;
+}
+
+
+CIdentifierExpr::~CIdentifierExpr()
+{
+ if (m_idContext)
+ m_idContext->Release();
+}
+
+
+
+CValue* CIdentifierExpr::Calculate()
+{
+ CValue* result = NULL;
+ if (m_idContext)
+ result = m_idContext->FindIdentifier(m_identifier);
+
+ return result;
+}
+
+
+
+bool CIdentifierExpr::MergeExpression(CExpression* otherexpr)
+{
+ return false;
+}
+
+
+
+unsigned char CIdentifierExpr::GetExpressionID()
+{
+ return CIDENTIFIEREXPRESSIONID;
+}
+
+
+
+bool CIdentifierExpr::NeedsRecalculated()
+{
+ return true;
+}
+
+
+
+CExpression* CIdentifierExpr::CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks)
+{
+ assertd(false); // not implemented yet
+ return NULL;
+}
+
+
+
+void CIdentifierExpr::ClearModified()
+{
+ assertd(false); // not implemented yet
+}
+
+
+
+void CIdentifierExpr::BroadcastOperators(VALUE_OPERATOR op)
+{
+ assertd(false); // not implemented yet
+}
diff --git a/source/gameengine/Expressions/IdentifierExpr.h b/source/gameengine/Expressions/IdentifierExpr.h
new file mode 100644
index 00000000000..dbffe7c02bc
--- /dev/null
+++ b/source/gameengine/Expressions/IdentifierExpr.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 __IDENTIFIER_EXPR
+#define __IDENTIFIER_EXPR
+
+#include "Expression.h"
+
+class CIdentifierExpr : public CExpression
+{
+ CValue* m_idContext;
+ STR_String m_identifier;
+public:
+ CIdentifierExpr(const STR_String& identifier,CValue* id_context);
+ virtual ~CIdentifierExpr();
+
+ virtual CValue* Calculate();
+ virtual bool MergeExpression(CExpression* otherexpr);
+ virtual unsigned char GetExpressionID();
+ virtual bool NeedsRecalculated();
+ virtual CExpression* CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks);
+ virtual void ClearModified();
+ virtual void BroadcastOperators(VALUE_OPERATOR op);
+};
+
+#endif //__IDENTIFIER_EXPR
+
diff --git a/source/gameengine/Expressions/IfExpr.cpp b/source/gameengine/Expressions/IfExpr.cpp
new file mode 100644
index 00000000000..5d3eb3641ca
--- /dev/null
+++ b/source/gameengine/Expressions/IfExpr.cpp
@@ -0,0 +1,144 @@
+// IfExpr.cpp: implementation of the CIfExpr class.
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#include "IfExpr.h"
+#include "EmptyValue.h"
+#include "ErrorValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+
+CIfExpr::CIfExpr()
+{
+}
+
+
+
+CIfExpr::CIfExpr(CExpression *guard, CExpression *e1, CExpression *e2)
+/*
+pre:
+effect: constructs an CifExpr-object corresponding to IF(guard, e1, e2)
+*/
+{
+ m_guard = guard;
+ m_e1 = e1;
+ m_e2 = e2;
+}
+
+
+
+CIfExpr::~CIfExpr()
+/*
+pre:
+effect: dereferences the object
+*/
+{
+ if (m_guard)
+ m_guard->Release();
+
+ if (m_e1)
+ m_e1->Release();
+
+ if (m_e2)
+ m_e2->Release();
+}
+
+
+
+CValue* CIfExpr::Calculate()
+/*
+pre:
+ret: a new object containing the value of m_e1 if m_guard is a boolean TRUE
+ a new object containing the value of m_e2 if m_guard is a boolean FALSE
+ an new errorvalue if m_guard is not a boolean
+*/
+{
+ CValue *guardval;
+ guardval = m_guard->Calculate();
+ STR_String text = guardval->GetText();
+ guardval->Release();
+
+ if (text == STR_String("TRUE"))
+ {
+ return m_e1->Calculate();
+ }
+ else if (text == STR_String("FALSE"))
+ {
+ return m_e2->Calculate();
+ }
+ else
+ {
+ return new CErrorValue("Guard should be of boolean type");
+ }
+}
+
+
+
+bool CIfExpr::MergeExpression(CExpression *otherexpr)
+{
+ assertd(false);
+ return false;
+}
+
+
+
+bool CIfExpr::IsInside(float x,float y,float z,bool bBorderInclude)
+{
+ assertd(false);
+ return false;
+}
+
+
+
+bool CIfExpr::NeedsRecalculated()
+{
+ return (m_guard->NeedsRecalculated() ||
+ m_e1->NeedsRecalculated() ||
+ m_e2->NeedsRecalculated());
+}
+
+
+
+CExpression* CIfExpr::CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks)
+{
+ assertd(false);
+ return NULL;
+}
+
+
+
+void CIfExpr::ClearModified()
+{
+ assertd(false);
+}
+
+
+
+void CIfExpr::BroadcastOperators(VALUE_OPERATOR op)
+{
+ assertd(false);
+}
+
+
+
+unsigned char CIfExpr::GetExpressionID()
+{
+ return CIFEXPRESSIONID;
+}
diff --git a/source/gameengine/Expressions/IfExpr.h b/source/gameengine/Expressions/IfExpr.h
new file mode 100644
index 00000000000..9ab13dca413
--- /dev/null
+++ b/source/gameengine/Expressions/IfExpr.h
@@ -0,0 +1,50 @@
+/*
+ * IfExpr.h: interface for the CIfExpr class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#if !defined(AFX_IFEXPR_H__1F691841_C5C7_11D1_A863_0000B4542BD8__INCLUDED_)
+#define AFX_IFEXPR_H__1F691841_C5C7_11D1_A863_0000B4542BD8__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+#include "Expression.h"
+
+class CIfExpr : public CExpression
+{
+ //PLUGIN_DECLARE_SERIAL_EXPRESSION (CIfExpr,CExpression)
+
+private:
+ CExpression *m_guard, *m_e1, *m_e2;
+
+public:
+ virtual bool MergeExpression(CExpression* otherexpr);
+ CIfExpr(CExpression *guard, CExpression *e1, CExpression *e2);
+ CIfExpr();
+
+ virtual unsigned char GetExpressionID();
+ virtual ~CIfExpr();
+ virtual CValue* Calculate();
+
+ virtual bool IsInside(float x,float y,float z,bool bBorderInclude=true);
+ virtual bool NeedsRecalculated();
+
+
+ virtual CExpression* CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks);
+ virtual void ClearModified();
+ virtual void BroadcastOperators(VALUE_OPERATOR op);
+};
+
+#endif // !defined(AFX_IFEXPR_H__1F691841_C5C7_11D1_A863_0000B4542BD8__INCLUDED_)
+
diff --git a/source/gameengine/Expressions/InputParser.cpp b/source/gameengine/Expressions/InputParser.cpp
new file mode 100644
index 00000000000..24033dd21a2
--- /dev/null
+++ b/source/gameengine/Expressions/InputParser.cpp
@@ -0,0 +1,654 @@
+// Parser.cpp: implementation of the CParser class.
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#include <stdlib.h>
+
+#include "MT_assert.h"
+
+#include "Value.h"
+#include "InputParser.h"
+#include "ErrorValue.h"
+#include "IntValue.h"
+#include "StringValue.h"
+#include "FloatValue.h"
+#include "BoolValue.h"
+#include "EmptyValue.h"
+#include "ConstExpr.h"
+#include "Operator2Expr.h"
+#include "Operator1Expr.h"
+#include "IdentifierExpr.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// this is disable at the moment, I expected a memleak from it, but the error-cleanup was the reason
+// well, looks we don't need it anyway, until maybe the Curved Surfaces are integrated into CSG
+// cool things like (IF(LOD==1,CCurvedValue,IF(LOD==2,CCurvedValue2)) etc...
+#include "IfExpr.h"
+
+
+#define NUM_PRIORITY 6
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CParser::CParser() : m_identifierContext(NULL)
+{
+}
+
+
+
+CParser::~CParser()
+{
+ if (m_identifierContext)
+ m_identifierContext->Release();
+}
+
+
+
+void CParser::ScanError(STR_String str)
+{
+ // sets the global variable errmsg to an errormessage with
+ // contents str, appending if it already exists
+ // AfxMessageBox("Parse Error:"+str,MB_ICONERROR);
+ if (errmsg)
+ errmsg = new COperator2Expr(VALUE_ADD_OPERATOR, errmsg, Error(str));
+ else
+ errmsg = Error(str);
+
+ sym = errorsym;
+}
+
+
+
+CExpression* CParser::Error(STR_String str)
+{
+ // makes and returns a new CConstExpr filled with an CErrorValue
+ // with string str
+ // AfxMessageBox("Error:"+str,MB_ICONERROR);
+ return new CConstExpr(new CErrorValue(str));
+}
+
+
+
+void CParser::NextCh()
+{
+ // sets the global variable ch to the next character, if it exists
+ // and increases the global variable chcount
+ chcount++;
+
+ if (chcount < text.Length())
+ ch = text[chcount];
+ else
+ ch = 0x00;
+}
+
+
+
+void CParser::TermChar(char c)
+{
+ // generates an error if the next char isn't the specified char c,
+ // otherwise, skip the char
+ if(ch == c)
+ {
+ NextCh();
+ }
+ else
+ {
+ STR_String str;
+ str.Format("Warning: %c expected\ncontinuing without it", c);
+ trace(str);
+ }
+}
+
+
+
+void CParser::DigRep()
+{
+ // changes the current character to the first character that
+ // isn't a decimal
+ while ((ch >= '0') && (ch <= '9'))
+ NextCh();
+}
+
+
+
+void CParser::CharRep()
+{
+ // changes the current character to the first character that
+ // isn't an alphanumeric character
+ while (((ch >= '0') && (ch <= '9'))
+ || ((ch >= 'a') && (ch <= 'z'))
+ || ((ch >= 'A') && (ch <= 'Z'))
+ || (ch == '.') || (ch == '_'))
+ NextCh();
+}
+
+
+
+void CParser::GrabString(int start)
+{
+ // puts part of the input string into the global variable
+ // const_as_string, from position start, to position chchount
+ const_as_string = text.Mid(start, chcount-start);
+}
+
+
+
+void CParser::NextSym()
+{
+ // sets the global variable sym to the next symbol, and
+ // if it is an operator
+ // sets the global variable opkind to the kind of operator
+ // if it is a constant
+ // sets the global variable constkind to the kind of operator
+ // if it is a reference to a cell
+ // sets the global variable cellcoord to the kind of operator
+
+ errmsg = NULL;
+ while(ch == ' ' || ch == 0x9)
+ NextCh();
+
+ switch(ch)
+ {
+ case '(':
+ sym = lbracksym; NextCh();
+ break;
+ case ')':
+ sym = rbracksym; NextCh();
+ break;
+ case ',':
+ sym = commasym; NextCh();
+ break;
+ case '+' :
+ sym = opsym; opkind = OPplus; NextCh();
+ break;
+ case '-' :
+ sym = opsym; opkind = OPminus; NextCh();
+ break;
+ case '*' :
+ sym = opsym; opkind = OPtimes; NextCh();
+ break;
+ case '/' :
+ sym = opsym; opkind = OPdivide; NextCh();
+ break;
+ case '&' :
+ sym = opsym; opkind = OPand; NextCh(); TermChar('&');
+ break;
+ case '|' :
+ sym = opsym; opkind = OPor; NextCh(); TermChar('|');
+ break;
+ case '=' :
+ sym = opsym; opkind = OPequal; NextCh(); TermChar('=');
+ break;
+ case '!' :
+ sym = opsym;
+ NextCh();
+ if (ch == '=')
+ {
+ opkind = OPunequal;
+ NextCh();
+ }
+ else
+ {
+ opkind = OPnot;
+ }
+ break;
+ case '>':
+ sym = opsym;
+ NextCh();
+ if (ch == '=')
+ {
+ opkind = OPgreaterequal;
+ NextCh();
+ }
+ else
+ {
+ opkind = OPgreater;
+ }
+ break;
+ case '<':
+ sym = opsym;
+ NextCh();
+ if (ch == '=') {
+ opkind = OPlessequal;
+ NextCh();
+ } else {
+ opkind = OPless;
+ }
+ break;
+ case '\"' : {
+ int start;
+ sym = constsym;
+ constkind = stringtype;
+ NextCh();
+ start = chcount;
+ while ((ch != '\"') && (ch != 0x0))
+ NextCh();
+ GrabString(start);
+ TermChar('\"'); // check for eol before '\"'
+ break;
+ }
+ case 0x0: sym = eolsym; break;
+ default:
+ {
+ int start;
+ start = chcount;
+ DigRep();
+ if ((start != chcount) || (ch == '.')) { // number
+ sym = constsym;
+ if (ch == '.') {
+ constkind = floattype;
+ NextCh();
+ DigRep();
+ }
+ else constkind = inttype;
+ if ((ch == 'e') || (ch == 'E')) {
+ int mark;
+ constkind = floattype;
+ NextCh();
+ if ((ch == '+') || (ch == '-')) NextCh();
+ mark = chcount;
+ DigRep();
+ if (mark == chcount) {
+ ScanError("Number expected after 'E'");
+ return;
+ }
+ }
+ GrabString(start);
+ } else if (((ch >= 'a') && (ch <= 'z'))
+ || ((ch >= 'A') && (ch <= 'Z')))
+ { // reserved word?
+ int start;
+ STR_String funstr;
+ start = chcount;
+ CharRep();
+ GrabString(start);
+ funstr = const_as_string;
+ funstr.Upper();
+ if (funstr == STR_String("SUM")) {
+ sym = sumsym;
+ }
+ else if (funstr == STR_String("NOT")) {
+ sym = opsym;
+ opkind = OPnot;
+ }
+ else if (funstr == STR_String("AND")) {
+ sym = opsym; opkind = OPand;
+ }
+ else if (funstr == STR_String("OR")) {
+ sym = opsym; opkind = OPor;
+ }
+ else if (funstr == STR_String("IF")) {
+ sym = ifsym;
+ } else if (funstr == STR_String("WHOMADE")) {
+ sym = whocodedsym;
+ } else if (funstr == STR_String("FALSE")) {
+ sym = constsym; constkind = booltype; boolvalue = false;
+ } else if (funstr == STR_String("TRUE")) {
+ sym = constsym; constkind = booltype; boolvalue = true;
+ } else {
+ sym = idsym;
+ //STR_String str;
+ //str.Format("'%s' makes no sense here", (const char*)funstr);
+ //ScanError(str);
+ }
+ } else { // unknown symbol
+ STR_String str;
+ str.Format("Unexpected character '%c'", ch);
+ NextCh();
+ ScanError(str);
+ return;
+ }
+ }
+ }
+}
+
+int CParser::MakeInt() {
+ // returns the integer representation of the value in the global
+ // variable const_as_string
+ // pre: const_as_string contains only numercal chars
+ return atoi(const_as_string);
+}
+
+STR_String CParser::Symbol2Str(int s) {
+ // returns a string representation of of symbol s,
+ // for use in Term when generating an error
+ switch(s) {
+ case errorsym: return "error";
+ case lbracksym: return "(";
+ case rbracksym: return ")";
+ case commasym: return ",";
+ case opsym: return "operator";
+ case constsym: return "constant";
+ case sumsym: return "SUM";
+ case ifsym: return "IF";
+ case whocodedsym: return "WHOMADE";
+ case eolsym: return "end of line";
+ case idsym: return "identifier";
+ default: return "unknown"; // should not happen
+ }
+}
+
+void CParser::Term(int s) {
+ // generates an error if the next symbol isn't the specified symbol s
+ // otherwise, skip the symbol
+ if(s == sym) NextSym();
+ else {
+ STR_String msg;
+ msg.Format("Warning: " + Symbol2Str(s) + " expected\ncontinuing without it");
+
+// AfxMessageBox(msg,MB_ICONERROR);
+
+ trace(msg);
+ }
+}
+
+int CParser::Priority(int optorkind) {
+ // returns the priority of an operator
+ // higher number means higher priority
+ switch(optorkind) {
+ case OPor: return 1;
+ case OPand: return 2;
+ case OPgreater:
+ case OPless:
+ case OPgreaterequal:
+ case OPlessequal:
+ case OPequal:
+ case OPunequal: return 3;
+ case OPplus:
+ case OPminus: return 4;
+ case OPtimes:
+ case OPdivide: return 5;
+ }
+ MT_assert(false);
+ return 0; // should not happen
+}
+
+CExpression *CParser::Ex(int i) {
+ // parses an expression in the imput, starting at priority i, and
+ // returns an CExpression, containing the parsed input
+ CExpression *e1 = NULL, *e2 = NULL;
+ int opkind2;
+
+ if (i < NUM_PRIORITY) {
+ e1 = Ex(i + 1);
+ while ((sym == opsym) && (Priority(opkind) == i)) {
+ opkind2 = opkind;
+ NextSym();
+ e2 = Ex(i + 1);
+ switch(opkind2) {
+ case OPplus: e1 = new COperator2Expr(VALUE_ADD_OPERATOR,e1, e2); break;
+ case OPminus: e1 = new COperator2Expr(VALUE_SUB_OPERATOR,e1, e2); break;
+ case OPtimes: e1 = new COperator2Expr(VALUE_MUL_OPERATOR,e1, e2); break;
+ case OPdivide: e1 = new COperator2Expr(VALUE_DIV_OPERATOR,e1, e2); break;
+ case OPand: e1 = new COperator2Expr(VALUE_AND_OPERATOR,e1, e2); break;
+ case OPor: e1 = new COperator2Expr(VALUE_OR_OPERATOR,e1, e2); break;
+ case OPequal: e1 = new COperator2Expr(VALUE_EQL_OPERATOR,e1, e2); break;
+ case OPunequal: e1 = new COperator2Expr(VALUE_NEQ_OPERATOR,e1, e2); break;
+ case OPgreater: e1 = new COperator2Expr(VALUE_GRE_OPERATOR,e1, e2); break;
+ case OPless: e1 = new COperator2Expr(VALUE_LES_OPERATOR,e1, e2); break;
+ case OPgreaterequal: e1 = new COperator2Expr(VALUE_GEQ_OPERATOR,e1, e2); break;
+ case OPlessequal: e1 = new COperator2Expr(VALUE_LEQ_OPERATOR,e1, e2); break;
+ default: MT_assert(false); break; // should not happen
+ }
+ }
+ } else if (i == NUM_PRIORITY) {
+ if ((sym == opsym)
+ && ( (opkind == OPminus) || (opkind == OPnot) || (opkind == OPplus) )
+ )
+ {
+ NextSym();
+ switch(opkind) {
+ /* +1 is also a valid number! */
+ case OPplus: e1 = new COperator1Expr(VALUE_POS_OPERATOR, Ex(NUM_PRIORITY)); break;
+ case OPminus: e1 = new COperator1Expr(VALUE_NEG_OPERATOR, Ex(NUM_PRIORITY)); break;
+ case OPnot: e1 = new COperator1Expr(VALUE_NOT_OPERATOR, Ex(NUM_PRIORITY)); break;
+ default: {
+ // should not happen
+ e1 = Error("operator +, - or ! expected");
+ }
+ }
+ }
+ else {
+ switch(sym) {
+ case constsym: {
+ switch(constkind) {
+ case booltype:
+ e1 = new CConstExpr(new CBoolValue(boolvalue));
+ break;
+ case inttype:
+ {
+ int temp;
+ temp = atoi(const_as_string);
+ e1 = new CConstExpr(new CIntValue(temp));
+ break;
+ }
+ case floattype:
+ {
+ double temp;
+ temp = atof(const_as_string);
+ e1 = new CConstExpr(new CFloatValue(temp));
+ break;
+ }
+ case stringtype:
+ e1 = new CConstExpr(new CStringValue(const_as_string,""));
+ break;
+ default :
+ MT_assert(false);
+ break;
+ }
+ NextSym();
+ break;
+ }
+ case lbracksym:
+ NextSym();
+ e1 = Ex(1);
+ Term(rbracksym);
+ break;
+ case ifsym:
+ {
+ CExpression *e3;
+ NextSym();
+ Term(lbracksym);
+ e1 = Ex(1);
+ Term(commasym);
+ e2 = Ex(1);
+ if (sym == commasym) {
+ NextSym();
+ e3 = Ex(1);
+ } else {
+ e3 = new CConstExpr(new CEmptyValue());
+ }
+ Term(rbracksym);
+ e1 = new CIfExpr(e1, e2, e3);
+ break;
+ }
+ case idsym:
+ {
+ e1 = new CIdentifierExpr(const_as_string,m_identifierContext);
+ NextSym();
+
+ break;
+ }
+ case errorsym:
+ {
+ MT_assert(!e1);
+ STR_String errtext="[no info]";
+ if (errmsg)
+ {
+ CValue* errmsgval = errmsg->Calculate();
+ errtext=errmsgval->GetText();
+ errmsgval->Release();
+
+ //e1 = Error(errmsg->Calculate()->GetText());//new CConstExpr(errmsg->Calculate());
+
+ if ( !(errmsg->Release()) )
+ {
+ errmsg=NULL;
+ } else {
+ // does this happen ?
+ MT_assert ("does this happen");
+ }
+ }
+ e1 = Error(errtext);
+
+ break;
+ }
+ default:
+ NextSym();
+ //return Error("Expression expected");
+ MT_assert(!e1);
+ e1 = Error("Expression expected");
+ }
+ }
+ }
+ return e1;
+}
+
+CExpression *CParser::Expr() {
+ // parses an expression in the imput, and
+ // returns an CExpression, containing the parsed input
+ return Ex(1);
+}
+
+CExpression* CParser::ProcessText
+(STR_String intext) {
+
+ // and parses the string in intext and returns it.
+
+
+ CExpression* expr;
+ text = intext;
+
+
+ chcount = 0;
+ if (text.Length() == 0) {
+ return NULL;
+ }
+
+ ch = text[0];
+ /*if (ch != '=') {
+ expr = new CConstExpr(new CStringValue(text));
+ *dependant = deplist;
+ return expr;
+ } else
+ */
+ // NextCh();
+ NextSym();
+ expr = Expr();
+ if (sym != eolsym) {
+ CExpression* oldexpr = expr;
+ expr = new COperator2Expr(VALUE_ADD_OPERATOR,
+ oldexpr, Error(STR_String("Extra characters after expression")));//new CConstExpr(new CErrorValue("Extra characters after expression")));
+ }
+ if (errmsg)
+ errmsg->Release();
+
+ return expr;
+}
+
+
+
+float CParser::GetFloat(STR_String txt)
+{
+ // returns parsed text into a float
+ // empty string returns -1
+
+// AfxMessageBox("parsed string="+txt);
+ CValue* val=NULL;
+ float result=-1;
+// String tmpstr;
+
+ CExpression* expr = ProcessText(txt);
+ if (expr) {
+ val = expr->Calculate();
+ result=val->GetNumber();
+
+
+
+ val->Release();
+ expr->Release();
+ }
+// tmpstr.Format("parseresult=%g",result);
+// AfxMessageBox(tmpstr);
+ return result;
+}
+
+CValue* CParser::GetValue(STR_String txt, bool bFallbackToText)
+{
+ // returns parsed text into a value,
+ // empty string returns NULL value !
+ // if bFallbackToText then unparsed stuff is put into text
+
+ CValue* result=NULL;
+ CExpression* expr = ProcessText(txt);
+ if (expr) {
+ result = expr->Calculate();
+ expr->Release();
+ }
+ if (result)
+ {
+ // if the parsed stuff lead to an errorvalue, don't return errors, just NULL
+ if (result->IsError()) {
+ result->Release();
+ result=NULL;
+ if (bFallbackToText) {
+ if (txt.Length()>0)
+ {
+ result = new CStringValue(txt,"");
+ }
+ }
+ }
+ }
+ return result;
+}
+
+void CParser::SetContext(CValue* context)
+{
+ if (m_identifierContext)
+ {
+ m_identifierContext->Release();
+ }
+ m_identifierContext = context;
+}
+
+
+
+
+PyObject* CParserPyMake(PyObject* ignored,PyObject* args)
+{
+ char* txt;
+ Py_Try(PyArg_ParseTuple(args,"s",&txt));
+ CParser parser;
+ CExpression* expr = parser.ProcessText(txt);
+ CValue* val = expr->Calculate();
+ expr->Release();
+ return val;
+}
+
+static PyMethodDef CParserMethods[] =
+{
+ { "calc", CParserPyMake , Py_NEWARGS},
+ { NULL,NULL} // Sentinel
+};
+
+extern "C" {
+ void initExpressionModule(void)
+ {
+ Py_InitModule("Expression",CParserMethods);
+ }
+}
+
diff --git a/source/gameengine/Expressions/InputParser.h b/source/gameengine/Expressions/InputParser.h
new file mode 100644
index 00000000000..4caa47cbb0c
--- /dev/null
+++ b/source/gameengine/Expressions/InputParser.h
@@ -0,0 +1,106 @@
+/*
+ * Parser.h: interface for the CParser class.
+ * Eindhoven University of Technology 1997
+ * OOPS team (Serge vd Boom, Erwin Coumans, Tom Geelen, Wynke Stuylemeier)
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#ifndef __INPUTPARSER_H__
+#define __INPUTPARSER_H__
+
+class CParser;
+#include "Expression.h"
+
+
+class CParser
+{
+public:
+ CParser();
+ virtual ~CParser();
+
+ float GetFloat(STR_String txt);
+ CValue* GetValue(STR_String txt, bool bFallbackToText=false);
+ CExpression* ProcessText(STR_String intext);
+ void SetContext(CValue* context);
+
+private:
+ enum symbols {
+ errorsym,
+ lbracksym,
+ rbracksym,
+ cellsym,
+ commasym,
+ opsym,
+ constsym,
+ sumsym,
+ ifsym,
+ whocodedsym,
+ eolsym,
+ idsym
+ }; // all kinds of symbols
+
+ enum optype {
+ OPplus,
+ OPminus,
+ OPtimes,
+ OPdivide,
+ OPand,
+ OPor,
+ OPequal,
+ OPunequal,
+ OPgreater,
+ OPless,
+ OPgreaterequal,
+ OPlessequal,
+ OPnot
+ }; // all kinds of operators
+
+ enum consttype {
+ booltype,
+ inttype,
+ floattype,
+ stringtype
+ }; // all kinds of constants
+
+ int sym, // current symbol
+ opkind, // kind of operator, if symbol is an operator
+ constkind; // kind of operator, if symbol is a constant
+
+ char ch; // current character
+ int chcount; // index to character in input string
+ CExpression *errmsg; // contains a errormessage, if scanner error
+
+ STR_String text, // contains a copy of the original text
+ const_as_string; // string representation of the symbol, if symbol is a constant
+ bool boolvalue; // value of the boolean, if symbol is a constant of type boolean
+ CValue* m_identifierContext;// context in which identifiers are looked up
+
+
+ void ScanError(STR_String str);
+ CExpression* Error(STR_String str);
+ void NextCh();
+ void TermChar(char c);
+ void DigRep();
+ void CharRep();
+ void GrabString(int start);
+ void NextSym();
+ int MakeInt();
+ STR_String Symbol2Str(int s);
+ void Term(int s);
+ int Priority(int optor);
+ CExpression *Ex(int i);
+ CExpression *Expr();
+
+};
+
+#endif
+
diff --git a/source/gameengine/Expressions/IntValue.cpp b/source/gameengine/Expressions/IntValue.cpp
new file mode 100644
index 00000000000..fbf4f4f59e0
--- /dev/null
+++ b/source/gameengine/Expressions/IntValue.cpp
@@ -0,0 +1,327 @@
+// IntValue.cpp: implementation of the CIntValue class.
+/*
+* Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+*
+* Permission to use, copy, modify, distribute and sell this software
+* and its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and
+* that both that copyright notice and this permission notice appear
+* in supporting documentation. Erwin Coumans makes no
+* representations about the suitability of this software for any
+* purpose. It is provided "as is" without express or implied warranty.
+*
+*/
+
+#include "IntValue.h"
+#include "ErrorValue.h"
+#include "FloatValue.h"
+#include "BoolValue.h"
+#include "StringValue.h"
+#include "VoidValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CIntValue::CIntValue()
+/*
+pre: false
+effect: constructs a new CIntValue
+*/
+{
+
+#ifdef _DEBUG_
+ m_textval = "Int illegal constructor";
+#endif
+ m_pstrRep=NULL;
+}
+
+
+
+CIntValue::CIntValue(int innie)
+/*
+pre:
+effect: constructs a new CIntValue containing int innie
+*/
+{
+ m_int = innie;
+ m_pstrRep=NULL;
+}
+
+
+
+CIntValue::CIntValue(int innie,STR_String name,AllocationTYPE alloctype)
+{
+ m_int = innie;
+ SetName(name);
+
+ if (alloctype==CValue::STACKVALUE)
+ {
+ CValue::DisableRefCount();
+ }
+ m_pstrRep=NULL;
+
+}
+
+
+
+CIntValue::~CIntValue()
+/*
+pre:
+effect: deletes the object
+*/
+{
+ if (m_pstrRep)
+ delete m_pstrRep;
+}
+
+
+
+CValue* CIntValue::Calc(VALUE_OPERATOR op, CValue *val)
+/*
+pre:
+ret: a new object containing the result of applying operator op to this
+object and val
+*/
+{
+ //return val->CalcInt(op, this);
+ switch (op) {
+ case VALUE_POS_OPERATOR:
+ return new CIntValue (m_int);
+ break;
+ case VALUE_NEG_OPERATOR:
+ return new CIntValue (-m_int);
+ break;
+ case VALUE_NOT_OPERATOR:
+ return new CErrorValue (op2str(op) + "only allowed on booleans");
+ break;
+ case VALUE_AND_OPERATOR:
+ case VALUE_OR_OPERATOR:
+ return new CErrorValue(val->GetText() + op2str(op) + "only allowed on booleans");
+ break;
+ default:
+ return val->CalcFinal(VALUE_INT_TYPE, op, this);
+ break;
+ }
+}
+
+
+
+CValue* CIntValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val)
+/*
+pre: the type of val is dtype
+ret: a new object containing the result of applying operator op to val and
+this object
+*/
+{
+ CValue *ret;
+
+ switch(dtype) {
+ case VALUE_EMPTY_TYPE:
+ case VALUE_INT_TYPE:
+ {
+ switch (op) {
+ case VALUE_ADD_OPERATOR:
+ ret = new CIntValue (((CIntValue *) val)->GetInt() + m_int);
+ break;
+ case VALUE_SUB_OPERATOR:
+ ret = new CIntValue (((CIntValue *) val)->GetInt() - m_int);
+ break;
+ case VALUE_MUL_OPERATOR:
+ ret = new CIntValue (((CIntValue *) val)->GetInt() * m_int);
+ break;
+ case VALUE_DIV_OPERATOR:
+ if (m_int == 0)
+ {
+ if (val->GetNumber() == 0)
+ {
+ ret = new CErrorValue("Not a Number");
+ } else
+ {
+ ret = new CErrorValue("Division by zero");
+ }
+ }
+ else
+ ret = new CIntValue (((CIntValue *) val)->GetInt() / m_int);
+ break;
+ case VALUE_EQL_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() == m_int);
+ break;
+ case VALUE_NEQ_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() != m_int);
+ break;
+ case VALUE_GRE_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() > m_int);
+ break;
+ case VALUE_LES_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() < m_int);
+ break;
+ case VALUE_GEQ_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() >= m_int);
+ break;
+ case VALUE_LEQ_OPERATOR:
+ ret = new CBoolValue(((CIntValue *) val)->GetInt() <= m_int);
+ break;
+ case VALUE_NEG_OPERATOR:
+ ret = new CIntValue (-m_int);
+ break;
+ case VALUE_POS_OPERATOR:
+ ret = new CIntValue (m_int);
+ break;
+ default:
+ ret = new CErrorValue("illegal operator. please send a bug report.");
+ break;
+ }
+ break;
+ }
+ case VALUE_FLOAT_TYPE:
+ {
+ switch (op) {
+ case VALUE_ADD_OPERATOR:
+ ret = new CFloatValue (((CFloatValue *) val)->GetFloat() + m_int);
+ break;
+ case VALUE_SUB_OPERATOR:
+ ret = new CFloatValue (((CFloatValue *) val)->GetFloat() - m_int);
+ break;
+ case VALUE_MUL_OPERATOR:
+ ret = new CFloatValue (((CFloatValue *) val)->GetFloat() * m_int);
+ break;
+ case VALUE_DIV_OPERATOR:
+ if (m_int == 0)
+ ret = new CErrorValue("Division by zero");
+ else
+ ret = new CFloatValue (((CFloatValue *) val)->GetFloat() / m_int);
+ break;
+ case VALUE_EQL_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() == m_int);
+ break;
+ case VALUE_NEQ_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() != m_int);
+ break;
+ case VALUE_GRE_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() > m_int);
+ break;
+ case VALUE_LES_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() < m_int);
+ break;
+ case VALUE_GEQ_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() >= m_int);
+ break;
+ case VALUE_LEQ_OPERATOR:
+ ret = new CBoolValue(((CFloatValue *) val)->GetFloat() <= m_int);
+ break;
+ default:
+ ret = new CErrorValue("illegal operator. please send a bug report.");
+ break;
+ }
+ break;
+ }
+ case VALUE_STRING_TYPE:
+ {
+ switch(op) {
+ case VALUE_ADD_OPERATOR:
+ ret = new CStringValue(val->GetText() + GetText(),"");
+ break;
+ case VALUE_EQL_OPERATOR:
+ case VALUE_NEQ_OPERATOR:
+ case VALUE_GRE_OPERATOR:
+ case VALUE_LES_OPERATOR:
+ case VALUE_GEQ_OPERATOR:
+ case VALUE_LEQ_OPERATOR:
+ ret = new CErrorValue("[Cannot compare string with integer]" + op2str(op) + GetText());
+ break;
+ default:
+ ret = new CErrorValue("[operator not allowed on strings]" + op2str(op) + GetText());
+ break;
+ }
+ break;
+ }
+ case VALUE_BOOL_TYPE:
+ ret = new CErrorValue("[operator not valid on boolean and integer]" + op2str(op) + GetText());
+ break;
+ /*
+ case VALUE_EMPTY_TYPE:
+ {
+ switch(op) {
+
+ case VALUE_ADD_OPERATOR:
+ ret = new CIntValue (m_int);
+ break;
+ case VALUE_SUB_OPERATOR:
+ ret = new CIntValue (-m_int);
+ break;
+ default:
+ {
+ ret = new CErrorValue(op2str(op) + GetText());
+ }
+ }
+ break;
+ }
+ */
+ case VALUE_ERROR_TYPE:
+ ret = new CErrorValue(val->GetText() + op2str(op) + GetText());
+ break;
+ default:
+ ret = new CErrorValue("illegal type. contact your dealer (if any)");
+ break;
+ }
+ return ret;
+}
+
+
+
+int CIntValue::GetInt()
+/*
+pre:
+ret: the int stored in the object
+*/
+{
+ return m_int;
+}
+
+
+
+float CIntValue::GetNumber()
+{
+ return (float) m_int;
+}
+
+
+
+const STR_String & CIntValue::GetText()
+{
+ if (!m_pstrRep)
+ m_pstrRep=new STR_String();
+ m_pstrRep->Format("%d",m_int);
+
+ return *m_pstrRep;
+}
+
+
+
+CValue* CIntValue::GetReplica() {
+ CIntValue* replica = new CIntValue(*this);
+ CValue::AddDataToReplica(replica);
+ replica->m_pstrRep = NULL;
+
+ return replica;
+}
+
+
+
+void CIntValue::SetValue(CValue* newval)
+{
+ m_int = (int)newval->GetNumber();
+ SetModified(true);
+}
+
+
+
+PyObject* CIntValue::ConvertValueToPython()
+{
+ return PyInt_FromLong(m_int);
+}
diff --git a/source/gameengine/Expressions/IntValue.h b/source/gameengine/Expressions/IntValue.h
new file mode 100644
index 00000000000..4fdc1089857
--- /dev/null
+++ b/source/gameengine/Expressions/IntValue.h
@@ -0,0 +1,60 @@
+/*
+ * IntValue.h: interface for the CIntValue class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#if !defined _INTVALUE_H
+#define _INTVALUE_H
+
+
+#include "Value.h"
+
+class CIntValue : public CPropValue
+{
+ //PLUGIN_DECLARE_SERIAL (CIntValue,CValue)
+
+public:
+ virtual const STR_String& GetText();
+ virtual float GetNumber();
+
+ int GetInt();
+ CIntValue();
+ CIntValue(int innie);
+ CIntValue(int innie,
+ STR_String name,
+ AllocationTYPE alloctype=CValue::HEAPVALUE);
+
+ virtual CValue* Calc(VALUE_OPERATOR op,
+ CValue *val);
+
+ virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype,
+ VALUE_OPERATOR op,
+ CValue *val);
+
+ virtual void SetValue(CValue* newval);
+
+ void Configure(CValue* menuvalue);
+ void AddConfigurationData(CValue* menuvalue);
+ virtual CValue* GetReplica();
+ virtual PyObject* ConvertValueToPython();
+
+protected:
+ virtual ~CIntValue();
+
+private:
+ int m_int;
+ STR_String* m_pstrRep;
+
+};
+
+#endif // !defined _INTVALUE_H
+
diff --git a/source/gameengine/Expressions/KX_HashedPtr.cpp b/source/gameengine/Expressions/KX_HashedPtr.cpp
new file mode 100644
index 00000000000..b1eeff20766
--- /dev/null
+++ b/source/gameengine/Expressions/KX_HashedPtr.cpp
@@ -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 *****
+ */
+
+#include "KX_HashedPtr.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+unsigned int KX_Hash(void * inDWord)
+{
+#if defined(_WIN64)
+ unsigned __int64 key = (unsigned __int64)inDWord;
+#else
+ unsigned long key = (unsigned long)inDWord;
+#endif
+
+ key += ~(key << 16);
+ key ^= (key >> 5);
+ key += (key << 3);
+ key ^= (key >> 13);
+ key += ~(key << 9);
+ key ^= (key >> 17);
+
+ return (unsigned int)(key & 0xffffffff);
+}
+
+
+CHashedPtr::CHashedPtr(void* val) : m_valptr(val)
+{
+}
+
+
+
+unsigned int CHashedPtr::hash() const
+{
+ return KX_Hash(m_valptr);
+}
diff --git a/source/gameengine/Expressions/KX_HashedPtr.h b/source/gameengine/Expressions/KX_HashedPtr.h
new file mode 100644
index 00000000000..06e86854d82
--- /dev/null
+++ b/source/gameengine/Expressions/KX_HashedPtr.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 __KX_HASHEDPTR
+#define __KX_HASHEDPTR
+
+unsigned int KX_Hash(void * inDWord);
+
+class CHashedPtr
+{
+ void* m_valptr;
+
+public:
+ CHashedPtr(void* val);
+
+ unsigned int hash() const;
+
+ inline friend bool operator ==( const CHashedPtr & rhs,const CHashedPtr & lhs)
+ {
+ return rhs.m_valptr == lhs.m_valptr;
+ }
+};
+
+#endif //__KX_HASHEDPTR
+
diff --git a/source/gameengine/Expressions/KX_Python.h b/source/gameengine/Expressions/KX_Python.h
new file mode 100644
index 00000000000..76c104390db
--- /dev/null
+++ b/source/gameengine/Expressions/KX_Python.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 KX_PYTHON_H
+#define KX_PYTHON_H
+
+//#define USE_DL_EXPORT
+#include "Python.h"
+
+#ifdef __FreeBSD__
+#include <osreldate.h>
+#if __FreeBSD_version > 500039
+#undef isalnum
+#undef isalpha
+#undef iscntrl
+#undef isdigit
+#undef isgraph
+#undef islower
+#undef isprint
+#undef ispunct
+#undef isspace
+#undef isupper
+#undef isxdigit
+#undef tolower
+#undef toupper
+#endif
+#endif
+
+#endif // KX_PYTHON_H
+
diff --git a/source/gameengine/Expressions/KX_Python_dynamic.h b/source/gameengine/Expressions/KX_Python_dynamic.h
new file mode 100644
index 00000000000..6ba31796e4f
--- /dev/null
+++ b/source/gameengine/Expressions/KX_Python_dynamic.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 KX_PYTHON_H
+#define KX_PYTHON_H
+
+//#define USE_DL_EXPORT
+#include "Python.h"
+
+#endif // KX_PYTHON_H
+
diff --git a/source/gameengine/Expressions/KX_Python_static.h b/source/gameengine/Expressions/KX_Python_static.h
new file mode 100644
index 00000000000..1a9682c8ef4
--- /dev/null
+++ b/source/gameengine/Expressions/KX_Python_static.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 KX_PYTHON_H
+#define KX_PYTHON_H
+
+#define USE_DL_EXPORT
+#include "Python.h"
+
+#endif // KX_PYTHON_H
+
diff --git a/source/gameengine/Expressions/ListValue.cpp b/source/gameengine/Expressions/ListValue.cpp
new file mode 100644
index 00000000000..bbf58a8a06e
--- /dev/null
+++ b/source/gameengine/Expressions/ListValue.cpp
@@ -0,0 +1,563 @@
+// ListValue.cpp: implementation of the CListValue class.
+//
+//////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#include "ListValue.h"
+#include "StringValue.h"
+#include "VoidValue.h"
+#include <algorithm>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if ((PY_MAJOR_VERSION == 2) &&(PY_MINOR_VERSION < 5))
+#define Py_ssize_t int
+#endif
+
+Py_ssize_t listvalue_bufferlen(PyObject* list)
+{
+ return (Py_ssize_t)( ((CListValue*)list)->GetCount());
+}
+
+PyObject* listvalue_buffer_item(PyObject* list,Py_ssize_t index)
+{
+ if (index >= 0 && index < ((CListValue*) list)->GetCount())
+ {
+ PyObject* pyobj = ((CListValue*) list)->GetValue(index)->ConvertValueToPython();
+ if (pyobj)
+ return pyobj;
+ else
+ return ((CListValue*) list)->GetValue(index)->AddRef();
+
+ }
+ Py_Error(PyExc_IndexError, "Python ListIndex out of range");
+ return NULL;
+}
+
+PyObject* listvalue_mapping_subscript(PyObject* list,PyObject* pyindex)
+{
+ if (PyString_Check(pyindex))
+ {
+ STR_String index(PyString_AsString(pyindex));
+ CValue *item = ((CListValue*) list)->FindValue(index);
+ if (item)
+ return (PyObject*) item;
+
+ }
+ if (PyInt_Check(pyindex))
+ {
+ int index = PyInt_AsLong(pyindex);
+ return listvalue_buffer_item(list, index);
+ }
+
+ PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */
+ STR_String index_str(PyString_AsString(pyindex_str));
+ PyErr_Format(PyExc_KeyError, "'%s' not in list", index_str.Ptr());
+ Py_DECREF(pyindex_str);
+ return NULL;
+}
+
+
+/* just slice it into a python list... */
+PyObject* listvalue_buffer_slice(PyObject* list,Py_ssize_t ilow, Py_ssize_t ihigh)
+{
+ int i, j;
+ PyListObject *newlist;
+
+ if (ilow < 0) ilow = 0;
+
+ int n = ((CListValue*) list)->GetCount();
+
+ if (ihigh >= n)
+ ihigh = n;
+ if (ihigh < ilow)
+ ihigh = ilow;
+
+ newlist = (PyListObject *) PyList_New(ihigh - ilow);
+ if (!newlist)
+ return NULL;
+
+ for (i = ilow, j = 0; i < ihigh; i++, j++)
+ {
+ PyObject* pyobj = ((CListValue*) list)->GetValue(i)->ConvertValueToPython();
+ if (!pyobj)
+ pyobj = ((CListValue*) list)->GetValue(i)->AddRef();
+ newlist->ob_item[j] = pyobj;
+ }
+ return (PyObject *) newlist;
+}
+
+
+
+static PyObject *
+listvalue_buffer_concat(PyObject * self, PyObject * other)
+{
+ // for now, we support CListValue concatenated with items
+ // and CListValue concatenated to Python Lists
+ // and CListValue concatenated with another CListValue
+
+ CListValue* listval = (CListValue*) self;
+ listval->AddRef();
+ if (other->ob_type == &PyList_Type)
+ {
+ bool error = false;
+
+ int i;
+ int numitems = PyList_Size(other);
+ for (i=0;i<numitems;i++)
+ {
+ PyObject* listitem = PyList_GetItem(other,i);
+ CValue* listitemval = listval->ConvertPythonToValue(listitem);
+ if (listitemval)
+ {
+ listval->Add(listitemval);
+ } else
+ {
+ error = true;
+ }
+ }
+
+ if (error)
+ Py_Error(PyExc_SystemError, "Python Error: couldn't add one or more items to a list");
+
+
+ } else
+ {
+ if (other->ob_type == &CListValue::Type)
+ {
+ // add items from otherlist to this list
+ CListValue* otherval = (CListValue*) other;
+
+
+ for (int i=0;i<otherval->GetCount();i++)
+ {
+ otherval->Add(listval->GetValue(i)->AddRef());
+ }
+ }
+ else
+ {
+ CValue* objval = listval->ConvertPythonToValue(other);
+ if (objval)
+ {
+ listval->Add(objval);
+ } else
+ {
+ Py_Error(PyExc_SystemError, "Python Error: couldn't add item to a list");
+ // bad luck
+ }
+ }
+ }
+
+ return self;
+}
+
+
+
+static PySequenceMethods listvalue_as_sequence = {
+ listvalue_bufferlen,//(inquiry)buffer_length, /*sq_length*/
+ listvalue_buffer_concat, /*sq_concat*/
+ NULL, /*sq_repeat*/
+ listvalue_buffer_item, /*sq_item*/
+ listvalue_buffer_slice, /*sq_slice*/
+ NULL, /*sq_ass_item*/
+ NULL /*sq_ass_slice*/
+};
+
+
+
+/* Is this one used ? */
+static PyMappingMethods instance_as_mapping = {
+ listvalue_bufferlen, /*mp_length*/
+ listvalue_mapping_subscript, /*mp_subscript*/
+ NULL /*mp_ass_subscript*/
+};
+
+
+
+PyTypeObject CListValue::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0, /*ob_size*/
+ "CListValue", /*tp_name*/
+ sizeof(CListValue), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ PyDestructor, /*tp_dealloc*/
+ 0, /*tp_print*/
+ __getattr, /*tp_getattr*/
+ __setattr, /*tp_setattr*/
+ 0, /*tp_compare*/
+ __repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ &listvalue_as_sequence, /*tp_as_sequence*/
+ &instance_as_mapping, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call */
+};
+
+
+
+PyParentObject CListValue::Parents[] = {
+ &CListValue::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+
+PyMethodDef CListValue::Methods[] = {
+ {"append", (PyCFunction)CListValue::sPyappend,METH_VARARGS},
+ {"reverse", (PyCFunction)CListValue::sPyreverse,METH_VARARGS},
+ {"index", (PyCFunction)CListValue::sPyindex,METH_VARARGS},
+ {"count", (PyCFunction)CListValue::sPycount,METH_VARARGS},
+
+ {NULL,NULL} //Sentinel
+};
+
+
+
+PyObject* CListValue::_getattr(const STR_String& attr) {
+ _getattr_up(CValue);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CListValue::CListValue(PyTypeObject *T )
+: CPropValue(T)
+{
+ m_bReleaseContents=true;
+}
+
+
+
+CListValue::~CListValue()
+{
+
+ if (m_bReleaseContents) {
+ for (unsigned int i=0;i<m_pValueArray.size();i++) {
+ m_pValueArray[i]->Release();
+ }
+ }
+}
+
+
+static STR_String gstrListRep=STR_String("List");
+
+const STR_String & CListValue::GetText()
+{
+ gstrListRep = "[";
+ STR_String commastr = "";
+
+ for (int i=0;i<GetCount();i++)
+ {
+ gstrListRep += commastr;
+ gstrListRep += GetValue(i)->GetText();
+ commastr = ",";
+ }
+ gstrListRep += "]";
+
+ return gstrListRep;
+}
+
+
+
+CValue* CListValue::GetReplica() {
+ CListValue* replica = new CListValue(*this);
+
+ CValue::AddDataToReplica(replica);
+
+ replica->m_bReleaseContents=true; // for copy, complete array is copied for now...
+ // copy all values
+ int numelements = m_pValueArray.size();
+ unsigned int i=0;
+ replica->m_pValueArray.resize(numelements);
+ for (i=0;i<m_pValueArray.size();i++)
+ replica->m_pValueArray[i] = m_pValueArray[i]->GetReplica();
+
+
+ return replica;
+};
+
+
+
+void CListValue::SetValue(int i, CValue *val)
+{
+ assertd(i < m_pValueArray.size());
+ m_pValueArray[i]=val;
+}
+
+
+
+void CListValue::Resize(int num)
+{
+ m_pValueArray.resize(num);
+}
+
+
+
+void CListValue::Remove(int i)
+{
+ assertd(i<m_pValueArray.size());
+ m_pValueArray.erase(m_pValueArray.begin()+i);
+}
+
+
+
+void CListValue::ReleaseAndRemoveAll()
+{
+ for (unsigned int i=0;i<m_pValueArray.size();i++)
+ m_pValueArray[i]->Release();
+ m_pValueArray.clear();//.Clear();
+}
+
+
+
+CValue* CListValue::FindValue(const STR_String & name)
+{
+ CValue* resultval = NULL;
+ int i=0;
+
+ while (!resultval && i < GetCount())
+ {
+ CValue* myval = GetValue(i);
+
+ if (myval->GetName() == name)
+ resultval = GetValue(i)->AddRef(); // add referencecount
+ else
+ i++;
+
+ }
+ return resultval;
+}
+
+
+
+bool CListValue::SearchValue(CValue *val)
+{
+ for (int i=0;i<GetCount();i++)
+ if (val == GetValue(i))
+ return true;
+ return false;
+}
+
+
+
+void CListValue::SetReleaseOnDestruct(bool bReleaseContents)
+{
+ m_bReleaseContents = bReleaseContents;
+}
+
+
+
+bool CListValue::RemoveValue(CValue *val)
+{
+ bool result=false;
+
+ for (int i=GetCount()-1;i>=0;i--)
+ if (val == GetValue(i))
+ {
+ Remove(i);
+ result=true;
+ }
+ return result;
+}
+
+
+
+void CListValue::MergeList(CListValue *otherlist)
+{
+
+ int numelements = this->GetCount();
+ int numotherelements = otherlist->GetCount();
+
+
+ Resize(numelements+numotherelements);
+
+ for (int i=0;i<numotherelements;i++)
+ {
+ SetValue(i+numelements,otherlist->GetValue(i)->AddRef());
+ }
+
+}
+
+
+
+PyObject* CListValue::Pyappend(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ PyObject* pyobj = NULL;
+ if (PyArg_ParseTuple(args,"O",&pyobj))
+ {
+ return listvalue_buffer_concat(self,pyobj);
+ }
+ else
+ {
+ return NULL;
+ }
+
+
+}
+
+
+
+PyObject* CListValue::Pyreverse(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ std::reverse(m_pValueArray.begin(),m_pValueArray.end());
+
+ Py_Return;
+
+}
+
+
+
+bool CListValue::CheckEqual(CValue* first,CValue* second)
+{
+ bool result = false;
+
+ CValue* eqval = ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second);
+ STR_String txt = eqval->GetText();
+ eqval->Release();
+ if (txt=="TRUE")
+ {
+ result = true;
+ }
+ return result;
+
+}
+
+
+
+PyObject* CListValue::Pyindex(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject* result = NULL;
+
+ PyObject* pyobj = NULL;
+ if (PyArg_ParseTuple(args,"O",&pyobj))
+ {
+
+ CValue* checkobj = ConvertPythonToValue(pyobj);
+ int numelem = GetCount();
+ for (int i=0;i<numelem;i++)
+ {
+ CValue* elem = GetValue(i);
+ if (CheckEqual(checkobj,elem))
+ {
+ result = PyInt_FromLong(i);
+ break;
+ }
+ }
+ checkobj->Release();
+ }
+
+ return result;
+
+}
+
+
+
+PyObject* CListValue::Pycount(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ int numfound = 0;
+
+ PyObject* pyobj = NULL;
+ if (PyArg_ParseTuple(args,"O",&pyobj))
+ {
+ CValue* checkobj = ConvertPythonToValue(pyobj);
+ int numelem = GetCount();
+ for (int i=0;i<numelem;i++)
+ {
+ CValue* elem = GetValue(i);
+ if (CheckEqual(checkobj,elem))
+ {
+ numfound ++;
+ }
+ }
+ checkobj->Release();
+ }
+
+ return PyInt_FromLong(numfound);
+}
+
+
+
+/* ---------------------------------------------------------------------
+ * Some stuff taken from the header
+ * --------------------------------------------------------------------- */
+CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val)
+{
+ assert(false); // todo: implement me!
+ return NULL;
+}
+
+
+
+CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype,
+ VALUE_OPERATOR op,
+ CValue* val)
+{
+ assert(false); // todo: implement me!
+ return NULL;
+}
+
+
+
+void CListValue::Add(CValue* value)
+{
+ m_pValueArray.push_back(value);
+}
+
+
+
+float CListValue::GetNumber()
+{
+ return -1;
+}
+
+
+
+void CListValue::SetModified(bool bModified)
+{
+ CValue::SetModified(bModified);
+ int numels = GetCount();
+
+ for (int i=0;i<numels;i++)
+ GetValue(i)->SetModified(bModified);
+}
+
+
+
+bool CListValue::IsModified()
+{
+ bool bmod = CValue::IsModified(); //normal own flag
+ int numels = GetCount();
+
+ for (int i=0;i<numels;i++)
+ bmod = bmod || GetValue(i)->IsModified();
+
+ return bmod;
+}
diff --git a/source/gameengine/Expressions/ListValue.h b/source/gameengine/Expressions/ListValue.h
new file mode 100644
index 00000000000..431f8f558a9
--- /dev/null
+++ b/source/gameengine/Expressions/ListValue.h
@@ -0,0 +1,77 @@
+/*
+ * ListValue.h: interface for the CListValue class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#if !defined _LISTVALUE_H
+#define _LISTVALUE_H
+
+#include "Value.h"
+
+class CListValue : public CPropValue
+{
+ Py_Header;
+ //PLUGIN_DECLARE_SERIAL (CListValue,CValue)
+
+public:
+ CListValue(PyTypeObject *T = &Type);
+ virtual ~CListValue();
+
+ void AddConfigurationData(CValue* menuvalue);
+ void Configure(CValue* menuvalue);
+ void Add(CValue* value);
+
+ /** @attention not implemented yet :( */
+ virtual CValue* Calc(VALUE_OPERATOR op,CValue *val);
+ virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype,
+ VALUE_OPERATOR op,
+ CValue* val);
+ virtual float GetNumber();
+ virtual CValue* GetReplica();
+
+public:
+ void MergeList(CListValue* otherlist);
+ bool RemoveValue(CValue* val);
+ void SetReleaseOnDestruct(bool bReleaseContents);
+ bool SearchValue(CValue* val);
+
+ CValue* FindValue(const STR_String & name);
+
+ void ReleaseAndRemoveAll();
+ virtual void SetModified(bool bModified);
+ virtual inline bool IsModified();
+ void Remove(int i);
+ void Resize(int num);
+ void SetValue(int i,CValue* val);
+ CValue* GetValue(int i){ assertd(i < m_pValueArray.size()); return m_pValueArray[i];}
+ int GetCount() { return m_pValueArray.size();};
+ virtual const STR_String & GetText();
+
+ bool CheckEqual(CValue* first,CValue* second);
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ KX_PYMETHOD(CListValue,append);
+ KX_PYMETHOD(CListValue,reverse);
+ KX_PYMETHOD(CListValue,index);
+ KX_PYMETHOD(CListValue,count);
+
+
+private:
+
+ std::vector<CValue*> m_pValueArray;
+ bool m_bReleaseContents;
+};
+
+#endif // !defined _LISTVALUE_H
+
diff --git a/source/gameengine/Expressions/Makefile b/source/gameengine/Expressions/Makefile
new file mode 100644
index 00000000000..18dca9a1c68
--- /dev/null
+++ b/source/gameengine/Expressions/Makefile
@@ -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 *****
+#
+#
+
+LIBNAME = expression
+DIR = $(OCGDIR)/gameengine/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I../../kernel/gen_system
+
diff --git a/source/gameengine/Expressions/Operator1Expr.cpp b/source/gameengine/Expressions/Operator1Expr.cpp
new file mode 100644
index 00000000000..85b3c669802
--- /dev/null
+++ b/source/gameengine/Expressions/Operator1Expr.cpp
@@ -0,0 +1,152 @@
+// Operator1Expr.cpp: implementation of the COperator1Expr class.
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#include "Operator1Expr.h"
+#include "EmptyValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+COperator1Expr::COperator1Expr()
+/*
+pre:
+effect: constucts an empty COperator1Expr
+*/
+{
+ m_lhs = NULL;
+}
+
+COperator1Expr::COperator1Expr(VALUE_OPERATOR op, CExpression * lhs)
+/*
+pre:
+effect: constucts a COperator1Expr with op and lhs in it
+*/
+{
+ m_lhs = lhs;
+ m_op = op;
+}
+
+COperator1Expr::~COperator1Expr()
+/*
+pre:
+effect: deletes the object
+*/
+{
+ if (m_lhs) m_lhs->Release();
+}
+
+CValue * COperator1Expr::Calculate()
+/*
+pre:
+ret: a new object containing the result of applying the operator m_op to the
+ value of m_lhs
+*/
+{
+ CValue *ret;
+ CValue *temp = m_lhs->Calculate();
+ CValue* empty = new CEmptyValue();
+ ret = empty->Calc(m_op, temp);
+ empty->Release();
+ temp->Release();
+
+ return ret;
+}
+
+/*
+bool COperator1Expr::IsInside(float x, float y, float z,bool bBorderInclude)
+{
+
+ bool result = true;
+ switch (m_op)
+ {
+
+ case VALUE_ADD_OPERATOR:
+ {
+
+ if (m_lhs)
+ {
+ result = result || m_lhs->IsInside(x,y,z,bBorderInclude);
+ }
+ break;
+ }
+ case VALUE_SUB_OPERATOR:
+ {
+ result = true;
+ if (m_lhs)
+ {
+ result = result && (!m_lhs->IsInside(x,y,z,bBorderInclude));
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+*/
+bool COperator1Expr::NeedsRecalculated() {
+
+ return m_lhs->NeedsRecalculated();
+
+}
+
+CExpression* COperator1Expr::CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks) {
+
+ CExpression* newlhs = m_lhs->CheckLink(brokenlinks);
+
+ if (newlhs)
+ {
+ if (newlhs==m_lhs) {
+ // not changed
+ } else {
+ // changed
+ //numchanges++;
+ newlhs->AddRef();
+
+ //m_lhs->Release();
+ brokenlinks.push_back(new CBrokenLinkInfo(&m_lhs,m_lhs));
+
+ m_lhs = newlhs;
+ }
+ return this;
+ } else {
+ //numchanges++;
+ AddRef();
+
+ return Release();
+ }
+
+}
+
+void COperator1Expr::BroadcastOperators(VALUE_OPERATOR op)
+{
+ if (m_lhs)
+ m_lhs->BroadcastOperators(m_op);
+}
+
+
+
+
+bool COperator1Expr::MergeExpression(CExpression *otherexpr)
+{
+ if (m_lhs)
+ return m_lhs->MergeExpression(otherexpr);
+
+ assertd(false); // should not get here, expression is not compatible for merge
+ return false;
+}
diff --git a/source/gameengine/Expressions/Operator1Expr.h b/source/gameengine/Expressions/Operator1Expr.h
new file mode 100644
index 00000000000..4a1deb0eca3
--- /dev/null
+++ b/source/gameengine/Expressions/Operator1Expr.h
@@ -0,0 +1,52 @@
+/*
+ * Operator1Expr.h: interface for the COperator1Expr class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#if !defined(AFX_OPERATOR1EXPR_H__A1653901_BF41_11D1_A51C_00A02472FC58__INCLUDED_)
+#define AFX_OPERATOR1EXPR_H__A1653901_BF41_11D1_A51C_00A02472FC58__INCLUDED_
+
+#include "Expression.h"
+
+class COperator1Expr : public CExpression
+{
+ //PLUGIN_DECLARE_SERIAL_EXPRESSION (COperator1Expr,CExpression)
+
+
+
+public:
+ virtual bool MergeExpression(CExpression* otherexpr);
+ virtual void BroadcastOperators(VALUE_OPERATOR op);
+
+ virtual unsigned char GetExpressionID() { return COPERATOR1EXPRESSIONID;};
+ CExpression* CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks);
+ //virtual bool IsInside(float x,float y,float z,bool bBorderInclude = true);
+ virtual bool NeedsRecalculated();
+ void ClearModified() {
+ if (m_lhs)
+ m_lhs->ClearModified();
+ }
+ virtual CValue* Calculate();
+ COperator1Expr(VALUE_OPERATOR op, CExpression *lhs);
+ COperator1Expr();
+ virtual ~COperator1Expr();
+
+
+
+private:
+ VALUE_OPERATOR m_op;
+ CExpression * m_lhs;
+};
+
+#endif // !defined(AFX_OPERATOR1EXPR_H__A1653901_BF41_11D1_A51C_00A02472FC58__INCLUDED_)
+
diff --git a/source/gameengine/Expressions/Operator2Expr.cpp b/source/gameengine/Expressions/Operator2Expr.cpp
new file mode 100644
index 00000000000..da0a3e9a9f9
--- /dev/null
+++ b/source/gameengine/Expressions/Operator2Expr.cpp
@@ -0,0 +1,277 @@
+// Operator2Expr.cpp: implementation of the COperator2Expr class.
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+// 31 dec 1998 - big update: try to use the cached data for updating, instead of
+// rebuilding completely it from left and right node. Modified flags and bounding boxes
+// have to do the trick
+// when expression is cached, there will be a call to UpdateCalc() instead of Calc()
+
+#include "Operator2Expr.h"
+#include "StringValue.h"
+#include "VoidValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+COperator2Expr::COperator2Expr(VALUE_OPERATOR op, CExpression *lhs, CExpression *rhs)
+:
+m_rhs(rhs),
+m_lhs(lhs),
+m_cached_calculate(NULL),
+m_op(op)
+/*
+pre:
+effect: constucts a COperator2Expr with op, lhs and rhs in it
+*/
+{
+
+}
+
+COperator2Expr::COperator2Expr():
+m_rhs(NULL),
+m_lhs(NULL),
+m_cached_calculate(NULL)
+
+/*
+pre:
+effect: constucts an empty COperator2Expr
+*/
+{
+
+}
+
+COperator2Expr::~COperator2Expr()
+/*
+pre:
+effect: deletes the object
+*/
+{
+ if (m_lhs)
+ m_lhs->Release();
+ if (m_rhs)
+ m_rhs->Release();
+ if (m_cached_calculate)
+ m_cached_calculate->Release();
+
+}
+CValue* COperator2Expr::Calculate()
+/*
+pre:
+ret: a new object containing the result of applying operator m_op to m_lhs
+and m_rhs
+*/
+{
+
+ bool leftmodified,rightmodified;
+ leftmodified = m_lhs->NeedsRecalculated();
+ rightmodified = m_rhs->NeedsRecalculated();
+
+ // if no modifications on both left and right subtree, and result is already calculated
+ // then just return cached result...
+ if (!leftmodified && !rightmodified && (m_cached_calculate))
+ {
+ // not modified, just return m_cached_calculate
+ } else {
+ // if not yet calculated, or modified...
+
+
+ if (m_cached_calculate) {
+ m_cached_calculate->Release();
+ m_cached_calculate=NULL;
+ }
+
+ CValue* ffleft = m_lhs->Calculate();
+ CValue* ffright = m_rhs->Calculate();
+
+ ffleft->SetOwnerExpression(this);//->m_pOwnerExpression=this;
+ ffright->SetOwnerExpression(this);//->m_pOwnerExpression=this;
+
+ m_cached_calculate = ffleft->Calc(m_op,ffright);
+
+ //if (m_cached_calculate)
+ // m_cached_calculate->Action(CValue::SETOWNEREXPR,&CVoidValue(this,false,CValue::STACKVALUE));
+
+ ffleft->Release();
+ ffright->Release();
+ }
+
+ return m_cached_calculate->AddRef();
+
+}
+
+/*
+bool COperator2Expr::IsInside(float x, float y, float z,bool bBorderInclude)
+{
+ bool inside;
+ inside = false;
+
+ switch (m_op)
+ {
+ case VALUE_ADD_OPERATOR: {
+ // inside = first || second; // optimized with early out if first is inside
+ // todo: calculate smallest leaf first ! is much faster...
+
+ bool second;//first ;//,second;
+
+ //first = m_lhs->IsInside(x,y,z) ;
+ second = m_rhs->IsInside(x,y,z,bBorderInclude) ;
+ if (second)
+ return true; //early out
+
+ // second = m_rhs->IsInside(x,y,z) ;
+
+ return m_lhs->IsInside(x,y,z,bBorderInclude) ;
+
+ break;
+ }
+
+ case VALUE_SUB_OPERATOR: {
+ //inside = first && !second; // optimized with early out
+ // todo: same as with add_operator: calc smallest leaf first
+
+ bool second;//first ;//,second;
+ //first = m_lhs->IsInside(x,y,z) ;
+ second = m_rhs->IsInside(x,y,z,bBorderInclude);
+ if (second)
+ return false;
+
+ // second space get subtracted -> negate!
+ //second = m_rhs->IsInside(x,y,z);
+
+ return (m_lhs->IsInside(x,y,z,bBorderInclude));
+
+
+ break;
+ }
+ default:{
+ assert(false);
+ // not yet implemented, only add or sub csg operations
+ }
+ }
+
+ return inside;
+}
+
+
+
+bool COperator2Expr::IsRightInside(float x, float y, float z,bool bBorderInclude) {
+
+ return m_rhs->IsInside(x,y,z,bBorderInclude) ;
+
+}
+
+bool COperator2Expr::IsLeftInside(float x, float y, float z,bool bBorderInclude) {
+ return m_lhs->IsInside(x,y,z,bBorderInclude);
+}
+*/
+bool COperator2Expr::NeedsRecalculated() {
+ // added some lines, just for debugging purposes, it could be a one-liner :)
+ //bool modleft
+ //bool modright;
+ assertd(m_lhs);
+ assertd(m_rhs);
+
+ //modright = m_rhs->NeedsRecalculated();
+ if (m_rhs->NeedsRecalculated()) // early out
+ return true;
+ return m_lhs->NeedsRecalculated();
+ //modleft = m_lhs->NeedsRecalculated();
+ //return (modleft || modright);
+
+}
+
+
+
+CExpression* COperator2Expr::CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks) {
+// if both children are 'dead', return NULL
+// if only one child is alive, return that child
+// if both childresn are alive, return this
+
+
+// bool leftalive = true,rightalive=true;
+ /* Does this mean the function will always bomb? */
+ assertd(false);
+ assert(m_lhs);
+ assert(m_rhs);
+/*
+ if (m_cached_calculate)
+ m_cached_calculate->Action(CValue::REFRESH_CACHE);
+
+ CExpression* newlhs = m_lhs->CheckLink(brokenlinks);
+ CExpression* newrhs = m_rhs->CheckLink(brokenlinks);
+
+ if (m_lhs != newlhs)
+ {
+ brokenlinks.push_back(new CBrokenLinkInfo(&m_lhs,m_lhs));
+ }
+
+ if (m_rhs != newrhs)
+ {
+ brokenlinks.push_back(new CBrokenLinkInfo(&m_rhs,m_rhs));
+ }
+
+
+
+ m_lhs = newlhs;
+ m_rhs = newrhs;
+
+ if (m_lhs && m_rhs) {
+ return this;
+ }
+
+ AddRef();
+ if (m_lhs)
+ return Release(m_lhs->AddRef());
+
+ if (m_rhs)
+ return Release(m_rhs->AddRef());
+/
+
+ */
+ return Release();
+
+
+
+}
+
+
+bool COperator2Expr::MergeExpression(CExpression *otherexpr)
+{
+ if (m_lhs)
+ {
+ if (m_lhs->GetExpressionID() == CExpression::CCONSTEXPRESSIONID)
+ {
+ // cross fingers ;) replace constexpr by new tree...
+ m_lhs->Release();
+ m_lhs = otherexpr->AddRef();
+ return true;
+ }
+ }
+
+ assertd(false);
+ return false;
+}
+
+
+void COperator2Expr::BroadcastOperators(VALUE_OPERATOR op)
+{
+ if (m_lhs)
+ m_lhs->BroadcastOperators(m_op);
+ if (m_rhs)
+ m_rhs->BroadcastOperators(m_op);
+}
diff --git a/source/gameengine/Expressions/Operator2Expr.h b/source/gameengine/Expressions/Operator2Expr.h
new file mode 100644
index 00000000000..4064890bbae
--- /dev/null
+++ b/source/gameengine/Expressions/Operator2Expr.h
@@ -0,0 +1,59 @@
+/*
+ * Operator2Expr.h: interface for the COperator2Expr class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#if !defined _OPERATOR2EXPR_H
+#define _OPERATOR2EXPR_H
+
+
+#include "Expression.h"
+#include "Value.h" // Added by ClassView
+
+class COperator2Expr : public CExpression
+{
+ //PLUGIN_DECLARE_SERIAL_EXPRESSION (COperator2Expr,CExpression)
+
+public:
+ virtual bool MergeExpression(CExpression* otherexpr);
+ virtual unsigned char GetExpressionID() { return COPERATOR2EXPRESSIONID;};
+ virtual void BroadcastOperators(VALUE_OPERATOR op);
+ CExpression* CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks);
+ //virtual bool IsInside(float x,float y,float z,bool bBorderInclude=true);
+ //virtual bool IsLeftInside(float x,float y,float z,bool bBorderInclude);
+ //virtual bool IsRightInside(float x,float y,float z,bool bBorderInclude);
+ bool NeedsRecalculated();
+ void ClearModified() {
+ if (m_lhs)
+ m_lhs->ClearModified();
+ if (m_rhs)
+ m_rhs->ClearModified();
+ }
+ virtual CValue* Calculate();
+ COperator2Expr(VALUE_OPERATOR op, CExpression *lhs, CExpression *rhs);
+ COperator2Expr();
+ virtual ~COperator2Expr();
+
+
+protected:
+ CExpression * m_rhs;
+ CExpression * m_lhs;
+ CValue* m_cached_calculate; // cached result
+
+private:
+ VALUE_OPERATOR m_op;
+
+};
+
+#endif // !defined _OPERATOR2EXPR_H
+
diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp
new file mode 100644
index 00000000000..1b343088446
--- /dev/null
+++ b/source/gameengine/Expressions/PyObjectPlus.cpp
@@ -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 *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef NO_EXP_PYTHON_EMBEDDING
+
+/*------------------------------
+ * PyObjectPlus cpp
+ *
+ * C++ library routines for Crawl 3.2
+ *
+ * Derived from work by
+ * David Redish
+ * graduate student
+ * Computer Science Department
+ * Carnegie Mellon University (CMU)
+ * Center for the Neural Basis of Cognition (CNBC)
+ * http://www.python.org/doc/PyCPP.html
+ *
+------------------------------*/
+#include <MT_assert.h>
+#include "stdlib.h"
+#include "PyObjectPlus.h"
+#include "STR_String.h"
+/*------------------------------
+ * PyObjectPlus Type -- Every class, even the abstract one should have a Type
+------------------------------*/
+
+PyTypeObject PyObjectPlus::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0, /*ob_size*/
+ "PyObjectPlus", /*tp_name*/
+ sizeof(PyObjectPlus), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ PyDestructor, /*tp_dealloc*/
+ 0, /*tp_print*/
+ __getattr, /*tp_getattr*/
+ __setattr, /*tp_setattr*/
+ 0, /*tp_compare*/
+ __repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call */
+};
+
+PyObjectPlus::~PyObjectPlus()
+{
+ if (ob_refcnt)
+ {
+ _Py_ForgetReference(this);
+ }
+// assert(ob_refcnt==0);
+}
+
+PyObjectPlus::PyObjectPlus(PyTypeObject *T) // constructor
+{
+ MT_assert(T != NULL);
+ this->ob_type = T;
+ _Py_NewReference(this);
+};
+
+/*------------------------------
+ * PyObjectPlus Methods -- Every class, even the abstract one should have a Methods
+------------------------------*/
+PyMethodDef PyObjectPlus::Methods[] = {
+ {"isA", (PyCFunction) sPy_isA, Py_NEWARGS},
+ {NULL, NULL} /* Sentinel */
+};
+
+/*------------------------------
+ * PyObjectPlus Parents -- Every class, even the abstract one should have parents
+------------------------------*/
+PyParentObject PyObjectPlus::Parents[] = {&PyObjectPlus::Type, NULL};
+
+/*------------------------------
+ * PyObjectPlus attributes -- attributes
+------------------------------*/
+PyObject *PyObjectPlus::_getattr(const STR_String& attr)
+{
+ if (attr == "__doc__" && GetType()->tp_doc)
+ return PyString_FromString(GetType()->tp_doc);
+
+ //if (streq(attr, "type"))
+ // return Py_BuildValue("s", (*(GetParents()))->tp_name);
+
+ return Py_FindMethod(Methods, this, const_cast<char *>(attr.ReadPtr()));
+}
+
+int PyObjectPlus::_delattr(const STR_String& attr)
+{
+ return 1;
+}
+
+int PyObjectPlus::_setattr(const STR_String& attr, PyObject *value)
+{
+ //return PyObject::_setattr(attr,value);
+ //cerr << "Unknown attribute" << endl;
+ return 1;
+}
+
+/*------------------------------
+ * PyObjectPlus repr -- representations
+------------------------------*/
+PyObject *PyObjectPlus::_repr(void)
+{
+ Py_Error(PyExc_SystemError, "Representation not overridden by object.");
+}
+
+/*------------------------------
+ * PyObjectPlus isA -- the isA functions
+------------------------------*/
+bool PyObjectPlus::isA(PyTypeObject *T) // if called with a Type, use "typename"
+{
+ return isA(T->tp_name);
+}
+
+
+bool PyObjectPlus::isA(const char *mytypename) // check typename of each parent
+{
+ int i;
+ PyParentObject P;
+ PyParentObject *Ps = GetParents();
+
+ for (P = Ps[i=0]; P != NULL; P = Ps[i++])
+ {
+ if (STR_String(P->tp_name) == STR_String(mytypename) )
+ return true;
+ }
+
+ return false;
+}
+
+PyObject *PyObjectPlus::Py_isA(PyObject *args) // Python wrapper for isA
+{
+ char *mytypename;
+ Py_Try(PyArg_ParseTuple(args, "s", &mytypename));
+ if(isA(mytypename))
+ {Py_INCREF(Py_True); return Py_True;}
+ else
+ {Py_INCREF(Py_False); return Py_False;};
+}
+
+#endif //NO_EXP_PYTHON_EMBEDDING
+
diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h
new file mode 100644
index 00000000000..026a58cdbca
--- /dev/null
+++ b/source/gameengine/Expressions/PyObjectPlus.h
@@ -0,0 +1,188 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 NO_EXP_PYTHON_EMBEDDING
+
+#ifndef _adr_py_lib_h_ // only process once,
+#define _adr_py_lib_h_ // even if multiply included
+
+#ifndef __cplusplus // c++ only
+#error Must be compiled with C++
+#endif
+
+#include "KX_Python.h"
+#include "STR_String.h"
+
+/*------------------------------
+ * Python defines
+------------------------------*/
+
+ // some basic python macros
+#define Py_NEWARGS 1
+#define Py_Return { Py_INCREF(Py_None); return Py_None;}
+static inline PyObject* Py_Success(bool truth)
+{
+ if (truth)
+ {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ Py_INCREF(Py_False);
+ return Py_False;
+}
+
+#define Py_Error(E, M) {PyErr_SetString(E, M); return NULL;}
+#define Py_Try(F) {if (!(F)) return NULL;}
+#define Py_Assert(A,E,M) {if (!(A)) {PyErr_SetString(E, M); return NULL;}}
+
+static inline void Py_Fatal(char *M) {
+ //cout << M << endl;
+ exit(-1);
+};
+
+ // This must be the first line of each
+ // PyC++ class
+#define Py_Header \
+ public: \
+ static PyTypeObject Type; \
+ static PyMethodDef Methods[]; \
+ static PyParentObject Parents[]; \
+ virtual PyTypeObject *GetType(void) {return &Type;}; \
+ virtual PyParentObject *GetParents(void) {return Parents;}
+
+ // This defines the _getattr_up macro
+ // which allows attribute and method calls
+ // to be properly passed up the hierarchy.
+#define _getattr_up(Parent) \
+ PyObject *rvalue = Py_FindMethod(Methods, this, const_cast<char*>(attr.ReadPtr())); \
+ if (rvalue == NULL) \
+ { \
+ PyErr_Clear(); \
+ return Parent::_getattr(attr); \
+ } \
+ else \
+ return rvalue
+
+/**
+ * These macros are helpfull when embedding Python routines. The second
+ * macro is one that also requires a documentation string
+ */
+#define KX_PYMETHOD(class_name, method_name) \
+ PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \
+ static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \
+ return ((class_name*) self)->Py##method_name(self, args, kwds); \
+ }; \
+
+#define KX_PYMETHOD_DOC(class_name, method_name) \
+ PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \
+ static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \
+ return ((class_name*) self)->Py##method_name(self, args, kwds); \
+ }; \
+ static char method_name##_doc[]; \
+
+/* The line above should remain empty */
+/**
+ * Method table macro (with doc)
+ */
+#define KX_PYMETHODTABLE(class_name, method_name) \
+ {#method_name , (PyCFunction) class_name::sPy##method_name, METH_VARARGS, class_name::method_name##_doc}
+
+/**
+ * Function implementation macro
+ */
+#define KX_PYMETHODDEF_DOC(class_name, method_name, doc_string) \
+char class_name::method_name##_doc[] = doc_string; \
+PyObject* class_name::Py##method_name(PyObject*, PyObject* args, PyObject*)
+
+
+/*------------------------------
+ * PyObjectPlus
+------------------------------*/
+typedef PyTypeObject * PyParentObject; // Define the PyParent Object
+
+class PyObjectPlus : public PyObject
+{ // The PyObjectPlus abstract class
+ Py_Header; // Always start with Py_Header
+
+public:
+ PyObjectPlus(PyTypeObject *T);
+
+ virtual ~PyObjectPlus(); // destructor
+ static void PyDestructor(PyObject *P) // python wrapper
+ {
+ delete ((PyObjectPlus *) P);
+ };
+
+// void INCREF(void) {
+// Py_INCREF(this);
+// }; // incref method
+// void DECREF(void) {
+// Py_DECREF(this);
+// }; // decref method
+
+ virtual PyObject *_getattr(const STR_String& attr); // _getattr method
+ static PyObject *__getattr(PyObject * PyObj, char *attr) // This should be the entry in Type.
+ {
+ return ((PyObjectPlus*) PyObj)->_getattr(STR_String(attr));
+ }
+
+ virtual int _delattr(const STR_String& attr);
+ virtual int _setattr(const STR_String& attr, PyObject *value); // _setattr method
+ static int __setattr(PyObject *PyObj, // This should be the entry in Type.
+ char *attr,
+ PyObject *value)
+ {
+ if (!value)
+ return ((PyObjectPlus*) PyObj)->_delattr(attr);
+ return ((PyObjectPlus*) PyObj)->_setattr(STR_String(attr), value);
+ }
+
+ virtual PyObject *_repr(void); // _repr method
+ static PyObject *__repr(PyObject *PyObj) // This should be the entry in Type.
+ {
+ return ((PyObjectPlus*) PyObj)->_repr();
+ }
+
+ // isA methods
+ bool isA(PyTypeObject *T);
+ bool isA(const char *mytypename);
+ PyObject *Py_isA(PyObject *args);
+ static PyObject *sPy_isA(PyObject *self, PyObject *args, PyObject *kwd)
+ {
+ return ((PyObjectPlus*)self)->Py_isA(args);
+ }
+};
+
+#endif // _adr_py_lib_h_
+
+#endif //NO_EXP_PYTHON_EMBEDDING
+
diff --git a/source/gameengine/Expressions/SConscript b/source/gameengine/Expressions/SConscript
new file mode 100644
index 00000000000..809ac31371e
--- /dev/null
+++ b/source/gameengine/Expressions/SConscript
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('*.cpp')
+
+incs ='. #source/kernel/gen_system #intern/string #intern/moto/include'
+incs += ' ' + env['BF_PYTHON_INC']
+
+env.BlenderLib ( 'bf_expressions', sources, Split(incs), [], libtype=['game','player'], priority = [45,125] )
diff --git a/source/gameengine/Expressions/StringValue.cpp b/source/gameengine/Expressions/StringValue.cpp
new file mode 100644
index 00000000000..1ef8c5629a0
--- /dev/null
+++ b/source/gameengine/Expressions/StringValue.cpp
@@ -0,0 +1,140 @@
+// StringValue.cpp: implementation of the CStringValue class.
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#include "StringValue.h"
+#include "BoolValue.h"
+#include "ErrorValue.h"
+#include "VoidValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CStringValue::CStringValue()
+/*
+pre: false
+effect: constructs a new CStringValue
+*/
+{
+ m_strString = "[Illegal String constructor call]";
+}
+
+CStringValue::CStringValue(STR_String txt,STR_String name,AllocationTYPE alloctype)
+/*
+pre:
+effect: constructs a new CStringValue containing text txt
+*/
+{
+ m_strString = txt;
+ SetName(name);
+
+ if (alloctype==CValue::STACKVALUE)
+ {
+ CValue::DisableRefCount();
+
+ }
+
+
+}
+
+
+CValue* CStringValue::Calc(VALUE_OPERATOR op, CValue *val)
+/*
+pre:
+ret: a new object containing the result of applying operator op to this
+object and val
+*/
+{
+ //return val->CalrcString(op, this);
+ return val->CalcFinal(VALUE_STRING_TYPE, op, this);
+}
+
+CValue* CStringValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val)
+/*
+pre: the type of val is dtype
+ret: a new object containing the result of applying operator op to val and
+this object
+*/
+{
+ CValue *ret;
+
+ if (op == VALUE_ADD_OPERATOR) {
+ if (dtype == VALUE_ERROR_TYPE)
+ ret = new CErrorValue(val->GetText() + op2str(op) + GetText());
+ else
+ ret = new CStringValue(val->GetText() + GetText(),"");
+ } else {
+
+ if (dtype == VALUE_STRING_TYPE || dtype == VALUE_EMPTY_TYPE) {
+ switch(op) {
+ case VALUE_EQL_OPERATOR:
+ ret = new CBoolValue(val->GetText() == GetText());
+ break;
+ case VALUE_NEQ_OPERATOR:
+ ret = new CBoolValue(val->GetText() != GetText());
+ break;
+ case VALUE_GRE_OPERATOR:
+ ret = new CBoolValue(val->GetText() > GetText());
+ break;
+ case VALUE_LES_OPERATOR:
+ ret = new CBoolValue(val->GetText() < GetText());
+ break;
+ case VALUE_GEQ_OPERATOR:
+ ret = new CBoolValue(val->GetText() >= GetText());
+ break;
+ case VALUE_LEQ_OPERATOR:
+ ret = new CBoolValue(val->GetText() <= GetText());
+ break;
+ default:
+ ret = new CErrorValue(val->GetText() + op2str(op) + "[operator not allowed on strings]");
+ break;
+ }
+ } else {
+ ret = new CErrorValue(val->GetText() + op2str(op) + "[operator not allowed on strings]");
+ }
+ }
+ return ret;
+}
+
+
+
+float CStringValue::GetNumber()
+{
+ return -1;
+}
+
+
+
+const STR_String & CStringValue::GetText()
+{
+ return m_strString;
+}
+
+bool CStringValue::IsEqual(const STR_String & other)
+{
+ return (m_strString == other);
+}
+
+CValue* CStringValue::GetReplica()
+{
+ CStringValue* replica = new CStringValue(*this);
+ CValue::AddDataToReplica(replica);
+ return replica;
+};
+
+
diff --git a/source/gameengine/Expressions/StringValue.h b/source/gameengine/Expressions/StringValue.h
new file mode 100644
index 00000000000..b824d4ef86d
--- /dev/null
+++ b/source/gameengine/Expressions/StringValue.h
@@ -0,0 +1,52 @@
+/*
+ * StringValue.h: interface for the CStringValue class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifndef __STRINGVALUE_H__
+#define __STRINGVALUE_H__
+
+#include "Value.h"
+
+class CStringValue : public CPropValue
+{
+
+
+ //PLUGIN_DECLARE_SERIAL(CStringValue,CValue)
+public:
+ /// Construction / destruction
+ CStringValue();
+ CStringValue (STR_String txt, STR_String name , AllocationTYPE alloctype = CValue::HEAPVALUE);
+
+ virtual ~CStringValue() {
+ };
+ /// CValue implementation
+ virtual bool IsEqual(const STR_String & other);
+ virtual const STR_String & GetText();
+ virtual float GetNumber();
+
+ virtual CValue* Calc(VALUE_OPERATOR op, CValue *val);
+ virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+ virtual void SetValue(CValue* newval) { m_strString = newval->GetText(); SetModified(true); };
+ virtual CValue* GetReplica();
+ virtual PyObject* ConvertValueToPython() {
+ return PyString_FromString(m_strString.Ptr());
+ }
+
+private:
+ // data member
+ STR_String m_strString;
+};
+
+#endif
+
diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp
new file mode 100644
index 00000000000..48898dfc1f5
--- /dev/null
+++ b/source/gameengine/Expressions/Value.cpp
@@ -0,0 +1,769 @@
+// Value.cpp: implementation of the CValue class.
+// developed at Eindhoven University of Technology, 1997
+// by the OOPS team
+//////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#include "Value.h"
+#include "FloatValue.h"
+#include "IntValue.h"
+#include "VectorValue.h"
+#include "VoidValue.h"
+#include "StringValue.h"
+#include "ErrorValue.h"
+#include "ListValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+double CValue::m_sZeroVec[3] = {0.0,0.0,0.0};
+
+#ifndef NO_EXP_PYTHON_EMBEDDING
+
+PyObject* cvalue_add(PyObject*v, PyObject*w)
+{
+ return ((CValue*)v)->Calc(VALUE_ADD_OPERATOR,(CValue*)w);
+}
+PyObject* cvalue_sub(PyObject*v, PyObject*w)
+{
+ return ((CValue*)v)->Calc(VALUE_SUB_OPERATOR,(CValue*)w);
+}
+PyObject* cvalue_mul(PyObject*v, PyObject*w)
+{
+ return ((CValue*)v)->Calc(VALUE_MUL_OPERATOR,(CValue*)w);
+}
+PyObject* cvalue_div(PyObject*v, PyObject*w)
+{
+ return ((CValue*)v)->Calc(VALUE_DIV_OPERATOR,(CValue*)w);
+}
+PyObject* cvalue_neg(PyObject*v)
+{
+ return ((CValue*)v)->Calc(VALUE_NEG_OPERATOR,(CValue*)v);
+}
+PyObject* cvalue_pos(PyObject*v)
+{
+ return ((CValue*)v)->Calc(VALUE_POS_OPERATOR,(CValue*)v);
+}
+
+
+int MyPyCompare (PyObject* v,PyObject* w)
+{
+ CValue* eqval = ((CValue*)v)->Calc(VALUE_EQL_OPERATOR,(CValue*)w);
+ STR_String txt = eqval->GetText();
+ eqval->Release();
+ if (txt=="TRUE")
+ return 0;
+ CValue* lessval = ((CValue*)v)->Calc(VALUE_LES_OPERATOR,(CValue*)w);
+ txt = lessval->GetText();
+ lessval->Release();
+ if (txt=="TRUE")
+ return -1;
+
+ return 1;
+}
+
+
+int cvalue_coerce(PyObject** pv,PyObject** pw)
+{
+ if (PyInt_Check(*pw)) {
+ double db = (double)PyInt_AsLong(*pw);
+ *pw = new CIntValue((int) db);
+ Py_INCREF(*pv);
+ return 0;
+ }
+ else if (PyLong_Check(*pw)) {
+ double db = PyLong_AsDouble(*pw);
+ *pw = new CFloatValue(db);
+ Py_INCREF(*pv);
+ return 0;
+ }
+ else if (PyFloat_Check(*pw)) {
+ double db = PyFloat_AsDouble(*pw);
+ *pw = new CFloatValue(db);
+ Py_INCREF(*pv);
+ return 0;
+ } else if (PyString_Check(*pw)) {
+ const STR_String str = PyString_AsString(*pw);
+ *pw = new CStringValue(str,"");
+ Py_INCREF(*pv);
+ return 0;
+ }
+ return 1; /* Can't do it */
+
+}
+static PyNumberMethods cvalue_as_number = {
+ (binaryfunc)cvalue_add, /*nb_add*/
+ (binaryfunc)cvalue_sub, /*nb_subtract*/
+ (binaryfunc)cvalue_mul, /*nb_multiply*/
+ (binaryfunc)cvalue_div, /*nb_divide*/
+ 0,//(binaryfunc)cvalue_remainder, /*nb_remainder*/
+ 0,//(binaryfunc)cvalue_divmod, /*nb_divmod*/
+ 0,//0,//0,//0,//(ternaryfunc)cvalue_pow, /*nb_power*/
+ (unaryfunc)cvalue_neg, /*nb_negative*/
+ 0,//(unaryfunc)cvalue_pos, /*nb_positive*/
+ 0,//(unaryfunc)cvalue_abs, /*nb_absolute*/
+ 0,//(inquiry)cvalue_nonzero, /*nb_nonzero*/
+ 0, /*nb_invert*/
+ 0, /*nb_lshift*/
+ 0, /*nb_rshift*/
+ 0, /*nb_and*/
+ 0, /*nb_xor*/
+ 0, /*nb_or*/
+ (coercion)cvalue_coerce, /*nb_coerce*/
+ 0,//(unaryfunc)cvalue_int, /*nb_int*/
+ 0,//(unaryfunc)cvalue_long, /*nb_long*/
+ 0,//(unaryfunc)cvalue_float, /*nb_float*/
+ 0, /*nb_oct*/
+ 0, /*nb_hex*/
+};
+
+
+PyTypeObject CValue::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "CValue",
+ sizeof(CValue),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ &MyPyCompare,
+ __repr,
+ &cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject CValue::Parents[] = {
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef CValue::Methods[] = {
+// { "printHello", (PyCFunction) CValue::sPyPrintHello, Py_NEWARGS},
+ { "getName", (PyCFunction) CValue::sPyGetName, Py_NEWARGS},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* CValue::PyGetName(PyObject* self,PyObject* args,PyObject* kwds)
+{
+ PyObject* pyname = PyString_FromString(this->GetName());
+ return pyname;
+}
+
+
+
+CValue::CValue(PyTypeObject *T)
+ : PyObjectPlus(T),
+#else
+CValue::CValue()
+:
+#endif //NO_EXP_PYTHON_EMBEDDING
+
+m_pNamedPropertyArray(NULL),
+m_refcount(1)
+/*
+pre: false
+effect: constucts a CValue
+*/
+{
+ //debug(gRefCountValue++) // debugging
+}
+
+
+
+CValue::~CValue()
+/*
+pre:
+effect: deletes the object
+*/
+{
+ ClearProperties();
+
+ assertd (m_refcount==0);
+}
+
+
+
+
+#define VALUE_SUB(val1, val2) (val1)->Calc(VALUE_SUB_OPERATOR, val2)
+#define VALUE_MUL(val1, val2) (val1)->Calc(VALUE_MUL_OPERATOR, val2)
+#define VALUE_DIV(val1, val2) (val1)->Calc(VALUE_DIV_OPERATOR, val2)
+#define VALUE_NEG(val1) (val1)->Calc(VALUE_NEG_OPERATOR, val1)
+#define VALUE_POS(val1) (val1)->Calc(VALUE_POS_OPERATOR, val1)
+
+
+STR_String CValue::op2str (VALUE_OPERATOR op)
+{
+ //pre:
+ //ret: the stringrepresentation of operator op
+
+ STR_String opmsg;
+ switch (op) {
+ case VALUE_ADD_OPERATOR:
+ opmsg = " + ";
+ break;
+ case VALUE_SUB_OPERATOR:
+ opmsg = " - ";
+ break;
+ case VALUE_MUL_OPERATOR:
+ opmsg = " * ";
+ break;
+ case VALUE_DIV_OPERATOR:
+ opmsg = " / ";
+ break;
+ case VALUE_NEG_OPERATOR:
+ opmsg = " -";
+ break;
+ case VALUE_POS_OPERATOR:
+ opmsg = " +";
+ break;
+ case VALUE_AND_OPERATOR:
+ opmsg = " & ";
+ break;
+ case VALUE_OR_OPERATOR:
+ opmsg = " | ";
+ break;
+ case VALUE_EQL_OPERATOR:
+ opmsg = " = ";
+ break;
+ case VALUE_NEQ_OPERATOR:
+ opmsg = " != ";
+ break;
+ case VALUE_NOT_OPERATOR:
+ opmsg = " !";
+ break;
+ default:
+ opmsg="Error in Errorhandling routine.";
+ // AfxMessageBox("Invalid operator");
+ break;
+ }
+ return opmsg;
+}
+
+
+
+
+
+//---------------------------------------------------------------------------------------------------------------------
+// Property Management
+//---------------------------------------------------------------------------------------------------------------------
+
+
+
+//
+// Set property <ioProperty>, overwrites and releases a previous property with the same name if needed
+//
+void CValue::SetProperty(const STR_String & name,CValue* ioProperty)
+{
+ // Check if somebody is setting an empty property
+ if (ioProperty==NULL)
+ {
+ trace("Warning:trying to set empty property!");
+ return;
+ }
+
+ // Make sure we have a property array
+ if (m_pNamedPropertyArray == NULL)
+ m_pNamedPropertyArray = new std::map<STR_String,CValue *>;
+
+ // Try to replace property (if so -> exit as soon as we replaced it)
+ CValue* oldval = (*m_pNamedPropertyArray)[name];
+ if (oldval)
+ {
+ oldval->Release();
+ }
+
+ // Add property at end of array
+ (*m_pNamedPropertyArray)[name] = ioProperty;//->Add(ioProperty);
+}
+
+
+
+//
+// Get pointer to a property with name <inName>, returns NULL if there is no property named <inName>
+//
+CValue* CValue::GetProperty(const STR_String & inName)
+{
+ // Check properties, as soon as we found it -> Return a pointer to the property
+ CValue* result = NULL;
+ if (m_pNamedPropertyArray)
+ {
+ std::map<STR_String,CValue*>::iterator it = (*m_pNamedPropertyArray).find(inName);
+ if (!( it==m_pNamedPropertyArray->end()))
+ {
+ result = (*it).second;
+ }
+
+ }
+ //for (int i=0; i<m_pValuePropertyArray->size(); i++)
+ // if ((*m_pValuePropertyArray)[i]->GetName() == inName)
+ // return (*m_pValuePropertyArray)[i];
+
+ // Did not find property with name <inName>, return NULL property pointer
+ return result;
+}
+
+
+
+//
+// Get text description of property with name <inName>, returns an empty string if there is no property named <inName>
+//
+STR_String CValue::GetPropertyText(const STR_String & inName,const STR_String& deftext)
+{
+ CValue *property = GetProperty(inName);
+ if (property)
+ return property->GetText();
+ else
+ return deftext;//String::sEmpty;
+}
+
+float CValue::GetPropertyNumber(const STR_String& inName,float defnumber)
+{
+ CValue *property = GetProperty(inName);
+ if (property)
+ return property->GetNumber();
+ else
+ return defnumber;
+}
+
+
+
+//
+// Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed
+//
+bool CValue::RemoveProperty(const STR_String & inName)
+{
+ // Check if there are properties at all which can be removed
+ if (m_pNamedPropertyArray == NULL)
+ return false;
+
+ // Scan all properties, as soon as we find one with <inName> -> Remove it
+// CValue* val = (*m_pNamedPropertyArray)[inName];
+ if (m_pNamedPropertyArray->erase(inName)) return true;
+
+ return false;
+}
+
+
+
+//
+// Clear all properties
+//
+void CValue::ClearProperties()
+{
+ // Check if we have any properties
+ if (m_pNamedPropertyArray == NULL)
+ return;
+
+ // Remove all properties
+ for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin();
+ !(it == m_pNamedPropertyArray->end());it++)
+ {
+ CValue* tmpval = (*it).second;
+ STR_String name = (*it).first;
+ tmpval->Release();
+ }
+
+ // Delete property array
+ delete m_pNamedPropertyArray;
+ m_pNamedPropertyArray=NULL;
+}
+
+
+
+//
+// Set all properties' modified flag to <inModified>
+//
+void CValue::SetPropertiesModified(bool inModified)
+{
+ int numprops = GetPropertyCount();
+ for (int i=0; i<numprops; i++)
+ GetProperty(i)->SetModified(inModified);
+}
+
+
+
+//
+// Check if any of the properties in this value have been modified
+//
+bool CValue::IsAnyPropertyModified()
+{
+ int numprops = GetPropertyCount();
+ for (int i=0;i<numprops;i++)
+ if (GetProperty(i)->IsModified())
+ return true;
+
+ return false;
+}
+
+
+
+//
+// Get property number <inIndex>
+//
+
+CValue* CValue::GetProperty(int inIndex)
+{
+
+ int count=0;
+ CValue* result = NULL;
+
+ if (m_pNamedPropertyArray)
+ {
+ for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin();
+ !(it == m_pNamedPropertyArray->end());it++)
+ {
+ if (count++==inIndex)
+ {
+ result = (*it).second;
+ break;
+ }
+ }
+
+ }
+ return result;
+}
+
+
+
+//
+// Get the amount of properties assiocated with this value
+//
+int CValue::GetPropertyCount()
+{
+ if (m_pNamedPropertyArray)
+ return m_pNamedPropertyArray->size();
+ else
+ return 0;
+}
+
+
+
+
+
+void CValue::CloneProperties(CValue *replica)
+{
+
+ if (m_pNamedPropertyArray)
+ {
+ replica->m_pNamedPropertyArray=NULL;
+ for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin();
+ !(it == m_pNamedPropertyArray->end());it++)
+ {
+
+ replica->SetProperty((*it).first,(*it).second->GetReplica());
+ }
+ }
+
+
+}
+
+
+
+
+
+
+double* CValue::GetVector3(bool bGetTransformedVec)
+{
+ assertd(false); // don;t get vector from me
+ return m_sZeroVec;//::sZero;
+}
+
+
+
+
+
+
+/*---------------------------------------------------------------------------------------------------------------------
+ Reference Counting
+---------------------------------------------------------------------------------------------------------------------*/
+//
+// Add a reference to this value
+//
+CValue *CValue::AddRef()
+{
+ // Increase global reference count, used to see at the end of the program
+ // if all CValue-derived classes have been dereferenced to 0
+ //debug(gRefCountValue++);
+ m_refcount++;
+ return this;
+}
+
+
+
+//
+// Release a reference to this value (when reference count reaches 0, the value is removed from the heap)
+//
+int CValue::Release()
+{
+ // Decrease global reference count, used to see at the end of the program
+ // if all CValue-derived classes have been dereferenced to 0
+ //debug(gRefCountValue--);
+
+ // Decrease local reference count, if it reaches 0 the object should be freed
+ if (--m_refcount > 0)
+ {
+ // Reference count normal, return new reference count
+ return m_refcount;
+ }
+ else
+ {
+ // Reference count reached 0, delete ourselves and return 0
+// MT_assert(m_refcount==0, "Reference count reached sub-zero, object released too much");
+ delete this;
+ return 0;
+ }
+
+}
+
+
+
+//
+// Disable reference counting for this value
+//
+void CValue::DisableRefCount()
+{
+ assertd(m_refcount == 1);
+ m_refcount--;
+
+ //debug(gRefCountValue--);
+ m_ValFlags.RefCountDisabled=true;
+}
+
+
+
+void CValue::AddDataToReplica(CValue *replica)
+{
+ replica->m_refcount = 1;
+
+ //register with Python
+ _Py_NewReference(replica);
+
+#ifdef _DEBUG
+ //gRefCountValue++;
+#endif
+ replica->m_ValFlags.RefCountDisabled = false;
+
+ replica->ReplicaSetName(GetName());
+
+ //copy all props
+ CloneProperties(replica);
+}
+
+
+
+CValue* CValue::FindIdentifier(const STR_String& identifiername)
+{
+
+ CValue* result = NULL;
+
+ int pos = 0;
+ // if a dot exists, explode the name into pieces to get the subcontext
+ if ((pos=identifiername.Find('.'))>=0)
+ {
+ const STR_String rightstring = identifiername.Right(identifiername.Length() -1 - pos);
+ const STR_String leftstring = identifiername.Left(pos);
+ CValue* tempresult = GetProperty(leftstring);
+ if (tempresult)
+ {
+ result=tempresult->FindIdentifier(rightstring);
+ }
+ } else
+ {
+ result = GetProperty(identifiername);
+ }
+ if (result)
+ return result->AddRef();
+ // warning here !!!
+ result = new CErrorValue(identifiername+" not found");
+ return result;
+}
+
+
+#ifndef NO_EXP_PYTHON_EMBEDDING
+
+
+static PyMethodDef CValueMethods[] =
+{
+ //{ "new", CValue::PyMake , Py_NEWARGS},
+ { NULL,NULL} // Sentinel
+};
+
+
+PyObject* CValue::_getattr(const STR_String& attr)
+{
+ CValue* resultattr = FindIdentifier(attr);
+ STR_String text;
+ if (resultattr)
+ {
+ if (resultattr->IsError())
+ {
+ resultattr->Release();
+ } else
+ {
+ // to avoid some compare problems, return a real pythonthing
+ PyObject* pyconvert = resultattr->ConvertValueToPython();
+ if (pyconvert)
+ {
+ resultattr->Release();
+ return pyconvert;
+ } else
+ {
+ // also check if it's already in pythoninterpreter!
+ return resultattr;
+ }
+
+ }
+ }
+ _getattr_up(PyObjectPlus);
+}
+
+CValue* CValue::ConvertPythonToValue(PyObject* pyobj)
+{
+
+ CValue* vallie = NULL;
+
+ PyTypeObject* type = pyobj->ob_type;
+
+ if (type == &PyList_Type)
+ {
+ CListValue* listval = new CListValue();
+ bool error = false;
+
+ int i;
+ int numitems = PyList_Size(pyobj);
+ for (i=0;i<numitems;i++)
+ {
+ PyObject* listitem = PyList_GetItem(pyobj,i); /* borrowed ref */
+ CValue* listitemval = ConvertPythonToValue(listitem);
+ if (listitemval)
+ {
+ listval->Add(listitemval);
+ } else
+ {
+ error = true;
+ }
+ }
+ if (!error)
+ {
+ // jippie! could be converted
+ vallie = listval;
+ } else
+ {
+ // list could not be converted... bad luck
+ listval->Release();
+ }
+
+ } else
+ if (type == &PyFloat_Type)
+ {
+ float fl;
+ PyArg_Parse(pyobj,"f",&fl);
+ vallie = new CFloatValue(fl);
+ } else
+ if (type==&PyInt_Type)
+ {
+ int innie;
+ PyArg_Parse(pyobj,"i",&innie);
+ vallie = new CIntValue(innie);
+ } else
+
+ if (type==&PyString_Type)
+ {
+ vallie = new CStringValue(PyString_AsString(pyobj),"");
+ } else
+ if (type==&CValue::Type || type==&CListValue::Type)
+ {
+ vallie = ((CValue*) pyobj)->AddRef();
+ }
+ return vallie;
+
+}
+
+int CValue::_delattr(const STR_String& attr)
+{
+ RemoveProperty(attr);
+ return 0;
+}
+
+int CValue::_setattr(const STR_String& attr,PyObject* pyobj)
+{
+ CValue* vallie = ConvertPythonToValue(pyobj);
+ if (vallie)
+ {
+ CValue* oldprop = GetProperty(attr);
+
+ if (oldprop)
+ {
+ oldprop->SetValue(vallie);
+ } else
+ {
+ SetProperty(attr,vallie->AddRef());
+ }
+ vallie->Release();
+ }
+
+ //PyObjectPlus::_setattr(attr,value);
+ return 0;
+};
+/*
+PyObject* CValue::PyMake(PyObject* ignored,PyObject* args)
+{
+
+ //Py_Try(PyArg_ParseTuple(args,"s",&name));
+ Py_INCREF(Py_None);
+ return Py_None;//new CValue();
+}
+*/
+
+extern "C" {
+ void initCValue(void)
+ {
+ Py_InitModule("CValue",CValueMethods);
+ }
+}
+
+
+
+#endif //NO_EXP_PYTHON_EMBEDDING
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+/* These implementations were moved out of the header */
+
+void CValue::SetOwnerExpression(class CExpression* expr)
+{
+ /* intentionally empty */
+}
+
+void CValue::SetColorOperator(VALUE_OPERATOR op)
+{
+ /* intentionally empty */
+}
+void CValue::SetValue(CValue* newval)
+{
+ // no one should get here
+ assertd(newval->GetNumber() == 10121969);
+}
+///////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
diff --git a/source/gameengine/Expressions/Value.h b/source/gameengine/Expressions/Value.h
new file mode 100644
index 00000000000..ccb9c34749d
--- /dev/null
+++ b/source/gameengine/Expressions/Value.h
@@ -0,0 +1,442 @@
+/*
+ * Value.h: interface for the CValue class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifdef WIN32
+#pragma warning (disable:4786)
+#endif //WIN32
+
+/////////////////////////////////////////////////////////////////////////////////////
+//// Baseclass CValue
+//// Together with CExpression, CValue and it's derived classes can be used to
+//// parse expressions into a parsetree with error detecting/correcting capabilities
+//// also expandible by a CFactory pluginsystem
+////
+//// Features:
+//// Reference Counting (AddRef() / Release())
+//// Calculations (Calc() / CalcFinal())
+//// Configuration (Configure())
+//// Serialization (EdSerialize() / EdIdSerialize() / EdPtrSerialize() and macro PLUGIN_DECLARE_SERIAL
+//// Property system (SetProperty() / GetProperty() / FindIdentifier())
+//// Replication (GetReplica())
+//// Flags (IsSelected() / IsModified() / SetSelected()...)
+////
+//// Some small editor-specific things added
+//// A helperclass CompressorArchive handles the serialization
+////
+/////////////////////////////////////////////////////////////////////////////////////
+#ifndef __VALUE_H__
+#define __VALUE_H__
+
+#include <map> // array functionality for the propertylist
+#include "STR_String.h" // STR_String class
+
+#ifndef GEN_NO_ASSERT
+#undef assert
+#define assert(exp) ((void)NULL)
+#endif
+
+
+#ifndef GEN_NO_TRACE
+#undef trace
+#define trace(exp) ((void)NULL)
+#endif
+
+#ifndef GEN_NO_DEBUG
+#undef debug
+#define debug(exp) ((void)NULL)
+#endif
+
+#ifndef GEN_NO_ASSERTD
+#undef assertd
+#define assertd(exp) ((void)NULL)
+#endif
+
+
+#ifndef USE_PRAGMA_ONCE
+#ifdef WIN32
+ #pragma once
+
+#endif //WIN32
+#endif
+
+#define EDITOR_LEVEL_VERSION 0x06
+
+enum VALUE_OPERATOR {
+
+ VALUE_ADD_OPERATOR, // +
+ VALUE_SUB_OPERATOR, // -
+ VALUE_MUL_OPERATOR, // *
+ VALUE_DIV_OPERATOR, // /
+ VALUE_NEG_OPERATOR, // -
+ VALUE_POS_OPERATOR, // +
+ VALUE_AND_OPERATOR, // &&
+ VALUE_OR_OPERATOR, // ||
+ VALUE_EQL_OPERATOR, // ==
+ VALUE_NEQ_OPERATOR, // !=
+ VALUE_GRE_OPERATOR, // >
+ VALUE_LES_OPERATOR, // <
+ VALUE_GEQ_OPERATOR, // >=
+ VALUE_LEQ_OPERATOR, // <=
+ VALUE_NOT_OPERATOR, // !
+ VALUE_NO_OPERATOR // no operation at all
+};
+
+enum VALUE_DATA_TYPE {
+ VALUE_NO_TYPE, // abstract baseclass
+ VALUE_INT_TYPE,
+ VALUE_FLOAT_TYPE,
+ VALUE_STRING_TYPE,
+ VALUE_BOOL_TYPE,
+ VALUE_ERROR_TYPE,
+ VALUE_EMPTY_TYPE,
+ VALUE_SOLID_TYPE,
+ VALUE_COMBISOLID_TYPE,
+ VALUE_VECTOR_TYPE,
+ VALUE_MENU_TYPE,
+ VALUE_ACTOR_TYPE,
+ VALUE_MAX_TYPE //only here to provide number of types
+};
+
+
+
+#ifdef _DEBUG
+//extern int gRefCountValue; // debugonly variable to check if all CValue Refences are Dereferenced at programexit
+#endif
+
+struct HashableInt
+{
+ HashableInt(int id) : mData(id) { }
+
+ unsigned long Hash() const { return 0;} ////}gHash(&mData, sizeof(int));}
+
+ bool operator==(HashableInt rhs) { return mData == rhs.mData; }
+
+ int mData;
+};
+
+
+//
+// Bitfield that stores the flags for each CValue derived class
+//
+struct ValueFlags {
+ ValueFlags() :
+ Modified(true),
+ Selected(false),
+ Affected(false),
+ ReleaseRequested(false),
+ Error(false),
+ RefCountDisabled(false),
+ HasProperties(false),
+ HasName(false),
+ Visible(true),
+ CustomFlag1(false),
+ CustomFlag2(false)
+ {
+ }
+
+ unsigned short Modified : 1;
+ unsigned short Selected : 1;
+ unsigned short Affected : 1;
+ unsigned short ReleaseRequested : 1;
+ unsigned short Error : 1;
+ unsigned short RefCountDisabled : 1;
+ unsigned short HasProperties : 1;
+ unsigned short HasName : 1;
+ unsigned short Visible : 1;
+ unsigned short CustomFlag1 : 1;
+ unsigned short CustomFlag2 : 1;
+
+
+};
+
+/**
+ * Base Class for all Actions performed on CValue's. Can be extended for undo/redo system in future.
+*/
+class CAction
+{
+public:
+ CAction() {
+ };
+ virtual ~CAction(){
+ };
+ virtual void Execute() const =0;
+};
+
+//
+// CValue
+//
+// Base class for all editor functionality, flexible object type that allows
+// calculations and uses reference counting for memory management.
+//
+//
+
+
+
+
+#ifndef NO_EXP_PYTHON_EMBEDDING
+#include "PyObjectPlus.h"
+#include "object.h"
+class CValue : public PyObjectPlus
+#else
+class CValue
+#endif //NO_EXP_PYTHON_EMBEDDING
+
+
+{
+#ifndef NO_EXP_PYTHON_EMBEDDING
+Py_Header;
+#endif //NO_EXP_PYTHON_EMBEDDING
+public:
+ enum AllocationTYPE {
+ STACKVALUE = 0,
+ HEAPVALUE = 1
+ };
+
+ enum DrawTYPE {
+ STARTFRAME = 0,
+ ENDFRAME = 1,
+ INTERFRAME = 2
+ };
+
+
+ // Construction / Destruction
+#ifndef NO_EXP_PYTHON_EMBEDDING
+
+ CValue(PyTypeObject *T = &Type);
+ //static PyObject* PyMake(PyObject*,PyObject*);
+ virtual PyObject *_repr(void)
+ {
+ return Py_BuildValue("s",(const char*)GetText());
+ }
+
+
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ void SpecialRelease()
+ {
+ int i=0;
+ if (ob_refcnt == 0)
+ {
+ _Py_NewReference(this);
+
+ } else
+ {
+ i++;
+ }
+ Release();
+ }
+ static void PyDestructor(PyObject *P) // python wrapper
+ {
+ ((CValue*)P)->SpecialRelease();
+ };
+
+ virtual PyObject* ConvertValueToPython() {
+ return NULL;
+ }
+
+ virtual CValue* ConvertPythonToValue(PyObject* pyobj);
+
+
+ virtual int _delattr(const STR_String& attr);
+ virtual int _setattr(const STR_String& attr,PyObject* value);
+
+ KX_PYMETHOD(CValue,GetName);
+
+#else
+ CValue();
+#endif //NO_EXP_PYTHON_EMBEDDING
+
+
+
+ // Expression Calculation
+ virtual CValue* Calc(VALUE_OPERATOR op, CValue *val) = 0;
+ virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) = 0;
+ virtual void SetOwnerExpression(class CExpression* expr);
+
+
+
+ void Execute(const CAction& a)
+ {
+ a.Execute();
+ };
+
+ /// Reference Counting
+ int GetRefCount() { return m_refcount; }
+ virtual CValue* AddRef(); // Add a reference to this value
+ virtual int Release(); // Release a reference to this value (when reference count reaches 0, the value is removed from the heap)
+
+ /// Property Management
+ virtual void SetProperty(const STR_String& name,CValue* ioProperty); // Set property <ioProperty>, overwrites and releases a previous property with the same name if needed
+ virtual CValue* GetProperty(const STR_String & inName); // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName>
+ STR_String GetPropertyText(const STR_String & inName,const STR_String& deftext=""); // Get text description of property with name <inName>, returns an empty string if there is no property named <inName>
+ float GetPropertyNumber(const STR_String& inName,float defnumber);
+ virtual bool RemoveProperty(const STR_String & inName); // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed
+ virtual void ClearProperties(); // Clear all properties
+
+ virtual void SetPropertiesModified(bool inModified); // Set all properties' modified flag to <inModified>
+ virtual bool IsAnyPropertyModified(); // Check if any of the properties in this value have been modified
+
+ virtual CValue* GetProperty(int inIndex); // Get property number <inIndex>
+ virtual int GetPropertyCount(); // Get the amount of properties assiocated with this value
+
+ virtual void CloneProperties(CValue* replica);
+ virtual CValue* FindIdentifier(const STR_String& identifiername);
+ /** Set the wireframe color of this value depending on the CSG
+ * operator type <op>
+ * @attention: not implemented */
+ virtual void SetColorOperator(VALUE_OPERATOR op);
+
+ virtual const STR_String & GetText() = 0;
+ virtual float GetNumber() = 0;
+ double* ZeroVector() { return m_sZeroVec; };
+ virtual double* GetVector3(bool bGetTransformedVec = false);
+
+ virtual STR_String GetName() = 0; // Retrieve the name of the value
+ virtual void SetName(STR_String name) = 0; // Set the name of the value
+ virtual void ReplicaSetName(STR_String name) = 0;
+ /** Sets the value to this cvalue.
+ * @attention this particular function should never be called. Why not abstract? */
+ virtual void SetValue(CValue* newval);
+ virtual CValue* GetReplica() =0;
+ //virtual CValue* Copy() = 0;
+
+
+ STR_String op2str(VALUE_OPERATOR op);
+
+ // setting / getting flags
+ inline void SetSelected(bool bSelected) { m_ValFlags.Selected = bSelected; }
+ virtual void SetModified(bool bModified) { m_ValFlags.Modified = bModified; }
+ virtual void SetAffected(bool bAffected=true) { m_ValFlags.Affected = bAffected; }
+ inline void SetReleaseRequested(bool bReleaseRequested) { m_ValFlags.ReleaseRequested=bReleaseRequested; }
+ inline void SetError(bool err) { m_ValFlags.Error=err; }
+ inline void SetVisible (bool vis) { m_ValFlags.Visible=vis; }
+
+ virtual bool IsModified() { return m_ValFlags.Modified; }
+ inline bool IsError() { return m_ValFlags.Error; }
+ virtual bool IsAffected() { return m_ValFlags.Affected || m_ValFlags.Modified; }
+ virtual bool IsSelected() { return m_ValFlags.Selected; }
+ inline bool IsReleaseRequested() { return m_ValFlags.ReleaseRequested; }
+ virtual bool IsVisible() { return m_ValFlags.Visible;}
+ virtual void SetCustomFlag1(bool bCustomFlag) { m_ValFlags.CustomFlag1 = bCustomFlag;};
+ virtual bool IsCustomFlag1() { return m_ValFlags.CustomFlag1;};
+
+ virtual void SetCustomFlag2(bool bCustomFlag) { m_ValFlags.CustomFlag2 = bCustomFlag;};
+ virtual bool IsCustomFlag2() { return m_ValFlags.CustomFlag2;};
+
+protected:
+ virtual void DisableRefCount(); // Disable reference counting for this value
+ virtual void AddDataToReplica(CValue* replica);
+ virtual ~CValue();
+private:
+ // Member variables
+ std::map<STR_String,CValue*>* m_pNamedPropertyArray; // Properties for user/game etc
+ ValueFlags m_ValFlags; // Frequently used flags in a bitfield (low memoryusage)
+ int m_refcount; // Reference Counter
+ static double m_sZeroVec[3];
+
+};
+
+
+
+//
+// Declare a CValue or CExpression or CWhatever to be serialized by the editor.
+//
+// This macro introduces the EdSerialize() function (which must be implemented by
+// the client) and the EdIdSerialize() function (which is implemented by this macro).
+//
+// The generated Copy() function returns a pointer to <root_base_class_name> type
+// of object. So, for *any* CValue-derived object this should be set to CValue,
+// for *any* CExpression-derived object this should be set to CExpression.
+//
+#define PLUGIN_DECLARE_SERIAL(class_name, root_base_class_name) \
+public: \
+ virtual root_base_class_name * Copy() { return new class_name; } \
+ virtual bool EdSerialize(CompressorArchive& arch,class CFactoryManager* facmgr,bool bIsStoring); \
+ virtual bool EdIdSerialize(CompressorArchive& arch,class CFactoryManager* facmgr,bool bIsStoring) \
+{ \
+ if (bIsStoring) \
+ arch.StoreString(#class_name); \
+ \
+ return false; \
+} \
+
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+// CPropValue is a CValue derived class, that implements the identification (String name)
+// SetName() / GetName(),
+// normal classes should derive from CPropValue, real lightweight classes straight from CValue
+
+
+class CPropValue : public CValue
+{
+public:
+
+#ifndef NO_EXP_PYTHON_EMBEDDING
+ CPropValue(PyTypeObject* T=&Type) :
+ CValue(T),
+#else
+ CPropValue() :
+#endif //NO_EXP_PYTHON_EMBEDDING
+ m_pstrNewName(NULL)
+
+ {
+ }
+
+ virtual ~CPropValue()
+ {
+ if (m_pstrNewName)
+ {
+ delete m_pstrNewName;
+ m_pstrNewName = NULL;
+ }
+ }
+
+ virtual void SetName(STR_String name) {
+ if (m_pstrNewName)
+ {
+ delete m_pstrNewName;
+ m_pstrNewName = NULL;
+ }
+ if (name.Length())
+ m_pstrNewName = new STR_String(name);
+ }
+ virtual void ReplicaSetName(STR_String name) {
+ m_pstrNewName=NULL;
+ if (name.Length())
+ m_pstrNewName = new STR_String(name);
+ }
+
+ virtual STR_String GetName() {
+ //STR_String namefromprop = GetPropertyText("Name");
+ //if (namefromprop.Length() > 0)
+ // return namefromprop;
+
+ if (m_pstrNewName)
+ {
+ return *m_pstrNewName;
+ }
+ return STR_String("");
+ }; // name of Value
+
+protected:
+ STR_String* m_pstrNewName; // Identification
+};
+
+#endif // !defined _VALUEBASECLASS_H
+
diff --git a/source/gameengine/Expressions/VectorValue.cpp b/source/gameengine/Expressions/VectorValue.cpp
new file mode 100644
index 00000000000..bea6902eba8
--- /dev/null
+++ b/source/gameengine/Expressions/VectorValue.cpp
@@ -0,0 +1,217 @@
+// VectorValue.cpp: implementation of the CVectorValue class.
+/*
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#pragma warning (disable:4786)
+#endif
+
+#include "Value.h"
+#include "VectorValue.h"
+#include "ErrorValue.h"
+//#include "MatrixValue.h"
+#include "VoidValue.h"
+#include "StringValue.h"
+//#include "FactoryManager.h"
+
+
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CVectorValue::CVectorValue(float x,float y,float z, AllocationTYPE alloctype)
+{
+ SetCustomFlag1(false);//FancyOutput=false;
+
+ if (alloctype == STACKVALUE)
+ {
+ CValue::DisableRefCount();
+ };
+
+ m_vec[KX_X] = m_transformedvec[KX_X] = x;
+ m_vec[KX_Y] = m_transformedvec[KX_Y] = y;
+ m_vec[KX_Z] = m_transformedvec[KX_Z] = z;
+
+}
+CVectorValue::CVectorValue(double vec[],STR_String name,AllocationTYPE alloctype) {
+
+ SetCustomFlag1(false);//FancyOutput=false;
+
+ m_vec[KX_X] = m_transformedvec[KX_X] = vec[KX_X];
+ m_vec[KX_Y] = m_transformedvec[KX_Y] = vec[KX_Y];
+ m_vec[KX_Z] = m_transformedvec[KX_Z] = vec[KX_Z];
+
+ if (alloctype == STACKVALUE)
+ {
+ CValue::DisableRefCount();
+
+ }
+
+ SetName(name);
+}
+
+CVectorValue::CVectorValue(double vec[],AllocationTYPE alloctype) {
+
+ SetCustomFlag1(false);//FancyOutput=false;
+
+ m_vec[KX_X] = m_transformedvec[KX_X] = vec[KX_X];
+ m_vec[KX_Y] = m_transformedvec[KX_Y] = vec[KX_Y];
+ m_vec[KX_Z] = m_transformedvec[KX_Z] = vec[KX_Z];
+
+ if (alloctype == STACKVALUE)
+ {
+ CValue::DisableRefCount();
+
+ }
+
+
+}
+CVectorValue::~CVectorValue()
+{
+
+}
+
+CValue* CVectorValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val)
+/*
+pre: the type of val is dtype
+ret: a new object containing the result of applying operator op to val and
+this object
+*/
+{
+ CValue *ret = NULL;
+
+ switch(op)
+ {
+ case VALUE_ADD_OPERATOR:
+ {
+ switch (dtype)
+ {
+ case VALUE_EMPTY_TYPE:
+ case VALUE_VECTOR_TYPE:
+ {
+ ret = new CVectorValue(
+ val->GetVector3()[KX_X] + GetVector3()[KX_X],
+ val->GetVector3()[KX_Y] + GetVector3()[KX_Y],
+ val->GetVector3()[KX_Z] + GetVector3()[KX_Z],
+ CValue::HEAPVALUE);
+ ret->SetName(GetName());
+ break;
+ }
+
+ default:
+ ret = new CErrorValue(val->GetText() + op2str(op) + GetText());
+ }
+ break;
+ }
+ case VALUE_MUL_OPERATOR:
+ {
+ switch (dtype)
+ {
+
+ case VALUE_EMPTY_TYPE:
+ case VALUE_VECTOR_TYPE:
+ {
+ //MT_Vector3 supports 'scaling' by another vector, instead of using general transform, Gino?
+ //ret = new CVectorValue(val->GetVector3().Scaled(GetVector3()),GetName());
+ break;
+ }
+ case VALUE_FLOAT_TYPE:
+ {
+ ret = new CVectorValue(
+ val->GetVector3()[KX_X] * GetVector3()[KX_X],
+ val->GetVector3()[KX_Y] * GetVector3()[KX_Y],
+ val->GetVector3()[KX_Z] * GetVector3()[KX_Z],
+ CValue::HEAPVALUE);
+ ret->SetName(GetName());
+ break;
+ }
+
+ default:
+ ret = new CErrorValue(val->GetText() + op2str(op) + GetText());
+ }
+ break;
+
+ }
+
+ default:
+ ret = new CErrorValue(val->GetText() + op2str(op) + GetText());
+ }
+
+
+ return ret;
+}
+
+float CVectorValue::GetNumber()
+{
+ return m_vec[KX_X];
+}
+
+
+double* CVectorValue::GetVector3(bool bGetTransformedVec)
+{
+ if (bGetTransformedVec)
+ return m_transformedvec;
+ // else
+ return m_vec;
+}
+
+
+
+
+
+void CVectorValue::SetVector(double newvec[])
+{
+ m_vec[KX_X] = m_transformedvec[KX_X] = newvec[KX_X];
+ m_vec[KX_Y] = m_transformedvec[KX_Y] = newvec[KX_Y];
+ m_vec[KX_Z] = m_transformedvec[KX_Z] = newvec[KX_Z];
+
+ SetModified(true);
+}
+
+
+void CVectorValue::SetValue(CValue *newval)
+{
+
+ double* newvec = ((CVectorValue*)newval)->GetVector3();
+ m_vec[KX_X] = m_transformedvec[KX_X] = newvec[KX_X];
+ m_vec[KX_Y] = m_transformedvec[KX_Y] = newvec[KX_Y];
+ m_vec[KX_Z] = m_transformedvec[KX_Z] = newvec[KX_Z];
+
+ SetModified(true);
+}
+
+static const STR_String gstrVectorStr=STR_String();
+const STR_String & CVectorValue::GetText()
+{
+ assertd(false);
+ return gstrVectorStr;
+}
+
+CValue* CVectorValue::GetReplica() {
+ CVectorValue* replica = new CVectorValue(*this);
+ CValue::AddDataToReplica(replica);
+ return replica;
+};
+
+/*void CVectorValue::Transform(rcMatrix4x4 mat)
+{
+ m_transformedvec = mat*m_vec;
+}
+*/
+
+
diff --git a/source/gameengine/Expressions/VectorValue.h b/source/gameengine/Expressions/VectorValue.h
new file mode 100644
index 00000000000..5d9b2a98891
--- /dev/null
+++ b/source/gameengine/Expressions/VectorValue.h
@@ -0,0 +1,85 @@
+/*
+ * VectorValue.h: interface for the CVectorValue class.
+ * $Id$
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#if !defined _VECTORVALUE_H
+#define _VECTORVALUE_H
+
+#include "Value.h"
+
+#define KX_X 0
+#define KX_Y 1
+#define KX_Z 2
+
+
+class CVectorValue : public CPropValue
+{
+ //PLUGIN_DECLARE_SERIAL(CVectorValue,CValue)
+
+public:
+ //void Transform(rcMatrix4x4 mat);
+ virtual void SetValue(CValue* newval);
+ void SetVector(double newvec[]);
+ void Configure(CValue* menuvalue);
+ virtual double* GetVector3(bool bGetTransformedVec=false);
+ virtual float GetNumber();
+
+ CValue* Calc(VALUE_OPERATOR op, CValue *val) {
+ return val->CalcFinal(VALUE_VECTOR_TYPE, op, this);
+ }
+
+ CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+
+
+ CVectorValue(double vec[],STR_String name,AllocationTYPE alloctype=CValue::HEAPVALUE);
+ CVectorValue() {};
+
+ CVectorValue(double vec[],AllocationTYPE alloctype=CValue::HEAPVALUE);
+ CVectorValue(float x,float y,float z, AllocationTYPE alloctype = CValue::HEAPVALUE);
+ virtual ~CVectorValue();
+ //virtual bool ExportT3D(File *txtfile,bool bNoName=false);
+ void AddConfigurationData(CValue* menuvalue);
+
+
+
+ virtual CValue* GetReplica();
+ virtual const STR_String & GetText();
+
+/*
+ void SnapPoint(float num,int snap)
+ {
+ if (num > 0) num += ((float)snap / 2);
+ else num -= ((float)snap / 2);
+ num = (long)(((long)(num / snap)) * snap);
+ };
+
+ void SnapPosition(const double snapvec[])
+ {
+
+ if (snapvec[KX_X] >= 1)
+ SnapPoint(m_vec[KX_X],snapvec[KX_X]);
+ if (snapvec[KX_Y] >= 1)
+ SnapPoint(m_vec[KX_Y],snapvec[KX_Y]);
+ if (snapvec[KX_Z] >= 1)
+ SnapPoint(m_vec[KX_Z],snapvec[KX_Z]);
+
+ }
+*/
+
+protected:
+ double m_vec[3];
+ double m_transformedvec[3];
+};
+
+#endif // !defined _VECTORVALUE_H
+
diff --git a/source/gameengine/Expressions/VoidValue.h b/source/gameengine/Expressions/VoidValue.h
new file mode 100644
index 00000000000..53fbd8b4f01
--- /dev/null
+++ b/source/gameengine/Expressions/VoidValue.h
@@ -0,0 +1,68 @@
+/**
+ * VoidValue.h: interface for the CVoidValue class.
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __VOIDVALUE_H__
+#define __VOIDVALUE_H__
+
+#include "Value.h"
+
+//
+// Void value, used to transport *any* type of data
+//
+class CVoidValue : public CPropValue
+{
+ //PLUGIN_DECLARE_SERIAL (CVoidValue,CValue)
+
+public:
+ /// Construction/destruction
+ CVoidValue() : m_bDeleteOnDestruct(false), m_pAnything(NULL) { }
+ CVoidValue(void * voidptr, bool bDeleteOnDestruct, AllocationTYPE alloctype) : m_bDeleteOnDestruct(bDeleteOnDestruct), m_pAnything(voidptr) { if (alloctype == STACKVALUE) CValue::DisableRefCount(); }
+ virtual ~CVoidValue(); // Destruct void value, delete memory if we're owning it
+
+ /// Value -> String or number
+ virtual const STR_String & GetText(); // Get string description of void value (unimplemented)
+ virtual float GetNumber() { return -1; }
+
+ /// Value calculation
+ virtual CValue* Calc(VALUE_OPERATOR op, CValue *val);
+ virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue* val);
+
+ /// Value replication
+ virtual CValue* GetReplica();
+
+ /// Data members
+ bool m_bDeleteOnDestruct;
+ void* m_pAnything;
+};
+
+#endif // !defined _VOIDVALUE_H
+
diff --git a/source/gameengine/GameLogic/CMakeLists.txt b/source/gameengine/GameLogic/CMakeLists.txt
new file mode 100644
index 00000000000..127edfc151d
--- /dev/null
+++ b/source/gameengine/GameLogic/CMakeLists.txt
@@ -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) 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 *.cpp Joystick/*.cpp)
+
+SET(INC
+ .
+ ../../../source/kernel/gen_system
+ ../../../intern/string
+ ../../../source/gameengine/Expressions
+ ../../../intern/moto/include
+ ${PYTHON_INC}
+ ${SDL_INC}
+)
+
+BLENDERLIB(bf_logic "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_logic', sources, Split(incs), [], libtype=['game','player'], priority=[30, 110] )
diff --git a/source/gameengine/GameLogic/Joystick/Makefile b/source/gameengine/GameLogic/Joystick/Makefile
new file mode 100644
index 00000000000..4de5f168ceb
--- /dev/null
+++ b/source/gameengine/GameLogic/Joystick/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 = Joystick
+DIR = $(OCGDIR)/gameengine/logic/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../Expressions
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+CPPFLAGS += $(NAN_SDLCFLAGS)
+
+CPPFLAGS += -I../../../kernel/gen_system
diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp
new file mode 100644
index 00000000000..071301514fb
--- /dev/null
+++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp
@@ -0,0 +1,374 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): snailrose.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include <SDL.h>
+
+#include "SCA_Joystick.h"
+#include "SCA_JoystickPrivate.h"
+
+
+SCA_Joystick::SCA_Joystick()
+ :
+ m_axis10(0),
+ m_axis11(0),
+ m_axis20(0),
+ m_axis21(0),
+ m_prec(3200),
+ m_buttonnum(-2),
+ m_hatdir(-2),
+ m_isinit(0),
+ m_istrig(0)
+{
+ m_private = new PrivateData();
+}
+
+
+SCA_Joystick::~SCA_Joystick()
+
+{
+ delete m_private;
+}
+
+
+bool SCA_Joystick::CreateJoystickDevice()
+{
+ bool init = false;
+ init = pCreateJoystickDevice();
+ return init;
+}
+
+
+void SCA_Joystick::DestroyJoystickDevice()
+{
+ if(m_isinit)
+ pDestroyJoystickDevice();
+}
+
+
+void SCA_Joystick::HandleEvents()
+{
+ if(m_isinit)
+ {
+ if(SDL_PollEvent(&m_private->m_event))
+ {
+ switch(m_private->m_event.type)
+ {
+ case SDL_JOYAXISMOTION:
+ HANDLE_AXISMOTION(OnAxisMotion);
+ break;
+ case SDL_JOYHATMOTION:
+ HANDLE_HATMOTION(OnHatMotion);
+ break;
+ case SDL_JOYBUTTONUP:
+ HANDLE_BUTTONUP(OnButtonUp);
+ break;
+ case SDL_JOYBUTTONDOWN:
+ HANDLE_BUTTONDOWN(OnButtonDown);
+ break;
+ case SDL_JOYBALLMOTION:
+ HANDLE_BALLMOTION(OnBallMotion);
+ break;
+ default:
+ HANDLE_NOEVENT(OnNothing);
+ break;
+ }
+ }
+ }
+}
+
+
+void SCA_Joystick::cSetPrecision(int val)
+{
+ m_prec = val;
+}
+
+
+bool SCA_Joystick::aRightAxisIsPositive(int axis)
+{
+ bool result;
+ int res = pGetAxis(axis,1);
+ res > m_prec? result = true: result = false;
+ m_istrig = result;
+ return result;
+}
+
+
+bool SCA_Joystick::aUpAxisIsPositive(int axis)
+{
+ bool result;
+ int res = pGetAxis(axis,0);
+ res < -m_prec? result = true : result = false;
+ m_istrig = result;
+ return result;
+}
+
+
+bool SCA_Joystick::aLeftAxisIsPositive(int axis)
+{
+ bool result;
+ int res = pGetAxis(axis,1);
+ res < -m_prec ? result = true : result = false;
+ m_istrig = result;
+ return result;
+}
+
+
+bool SCA_Joystick::aDownAxisIsPositive(int axis)
+{
+ bool result;
+ int res = pGetAxis(axis,0);
+ res > m_prec ? result = true:result = false;
+ m_istrig = result;
+ return result;
+}
+
+
+bool SCA_Joystick::aButtonPressIsPositive(int button)
+{
+ bool result;
+ SDL_JoystickGetButton(m_private->m_joystick, button)? result = true:result = false;
+ m_istrig = result;
+ return result;
+}
+
+
+bool SCA_Joystick::aButtonReleaseIsPositive(int button)
+{
+ bool result;
+ SDL_JoystickGetButton(m_private->m_joystick, button)? result = false : result = true;
+ m_istrig = result;
+ return result;
+}
+
+
+bool SCA_Joystick::aHatIsPositive(int dir)
+{
+ bool result;
+ int res = pGetHat(dir);
+ res == dir? result = true : result = false;
+ m_istrig = result;
+ return result;
+}
+
+
+int SCA_Joystick::pGetButtonPress(int button)
+{
+ if(button == m_buttonnum)
+ return m_buttonnum;
+ return -2;
+}
+
+
+int SCA_Joystick::pGetButtonRelease(int button)
+{
+ if(button == m_buttonnum)
+ return m_buttonnum;
+ return -2;
+}
+
+
+int SCA_Joystick::pGetHat(int direction)
+{
+ if(direction == m_hatdir){
+ return m_hatdir;
+ }
+ return 0;
+}
+
+
+bool SCA_Joystick::GetJoyAxisMotion()
+{
+ bool result = false;
+ if(m_isinit){
+ if(SDL_PollEvent(&m_private->m_event)){
+ switch(m_private->m_event.type)
+ {
+ case SDL_JOYAXISMOTION:
+ result = true;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+
+bool SCA_Joystick::GetJoyButtonPress()
+{
+ bool result = false;
+ if(m_isinit){
+ if(SDL_PollEvent(&m_private->m_event)){
+ switch(m_private->m_event.type)
+ {
+ case SDL_JOYBUTTONDOWN:
+ result = true;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+
+bool SCA_Joystick::GetJoyButtonRelease()
+{
+ bool result = false;
+ if(m_isinit)
+ {
+ if(SDL_PollEvent(&m_private->m_event)){
+ switch(m_private->m_event.type)
+ {
+ case SDL_JOYBUTTONUP:
+ result = true;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+
+bool SCA_Joystick::GetJoyHatMotion()
+{
+ bool result = false;
+ if(m_isinit){
+ if(SDL_PollEvent(&m_private->m_event)){
+ switch(m_private->m_event.type)
+ {
+ case SDL_JOYHATMOTION:
+ result = true;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+
+int SCA_Joystick::GetNumberOfAxes()
+{
+ int number;
+ if(m_isinit){
+ if(m_private->m_joystick){
+ number = SDL_JoystickNumAxes(m_private->m_joystick);
+ return number;
+ }
+ }
+ return -1;
+}
+
+
+int SCA_Joystick::GetNumberOfButtons()
+{
+ int number;
+ if(m_isinit){
+ if(m_private->m_joystick){
+ number = SDL_JoystickNumButtons(m_private->m_joystick);
+ return number;
+ }
+ }
+ return -1;
+}
+
+
+int SCA_Joystick::GetNumberOfHats()
+{
+ int number;
+ if(m_isinit){
+ if(m_private->m_joystick){
+ number = SDL_JoystickNumHats(m_private->m_joystick);
+ return number;
+ }
+ }
+ return -1;
+}
+
+bool SCA_Joystick::pCreateJoystickDevice()
+{
+ if(m_isinit == false){
+ if(SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO ) == -1 ){
+ echo("Error-Initializing-SDL: " << SDL_GetError());
+ return false;
+ }
+ if(SDL_NumJoysticks() > 0){
+ for(int i=0; i<SDL_NumJoysticks();i++){
+ m_private->m_joystick = SDL_JoystickOpen(i);
+ SDL_JoystickEventState(SDL_ENABLE);
+ m_numjoys = i;
+ }
+ echo("Joystick-initialized");
+ m_isinit = true;
+ return true;
+ }else{
+ echo("Joystick-Error: " << SDL_NumJoysticks() << " avaiable joystick(s)");
+ return false;
+ }
+ }
+ return false;
+}
+
+
+void SCA_Joystick::pDestroyJoystickDevice()
+{
+ echo("Closing-");
+ for(int i=0; i<SDL_NumJoysticks(); i++){
+ if(SDL_JoystickOpened(i)){
+ SDL_JoystickClose(m_private->m_joystick);
+ }
+ }
+ SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO );
+}
+
+
+void SCA_Joystick::pFillAxes()
+{
+ if(GetNumberOfAxes() == 1){
+ m_axis10 = SDL_JoystickGetAxis(m_private->m_joystick, 0);
+ m_axis11 = SDL_JoystickGetAxis(m_private->m_joystick, 1);
+ }else if(GetNumberOfAxes() > 1){
+ m_axis10 = SDL_JoystickGetAxis(m_private->m_joystick, 0);
+ m_axis11 = SDL_JoystickGetAxis(m_private->m_joystick, 1);
+ m_axis20 = SDL_JoystickGetAxis(m_private->m_joystick, 2);
+ m_axis21 = SDL_JoystickGetAxis(m_private->m_joystick, 3);
+ }else{
+ m_axis10 = 0;m_axis11 = 0;
+ m_axis20 = 0;m_axis21 = 0;
+ }
+}
+
+
+int SCA_Joystick::pGetAxis(int axisnum, int udlr)
+{
+ if(axisnum == 1 && udlr == 1)return m_axis10; //u/d
+ if(axisnum == 1 && udlr == 0)return m_axis11; //l/r
+ if(axisnum == 2 && udlr == 0)return m_axis20; //...
+ if(axisnum == 2 && udlr == 1)return m_axis21;
+ return 0;
+}
+
diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.h b/source/gameengine/GameLogic/Joystick/SCA_Joystick.h
new file mode 100644
index 00000000000..2d2a713fe00
--- /dev/null
+++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.h
@@ -0,0 +1,388 @@
+/**
+
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+
+ *
+
+ * This program is free software; you can redistribute it and/or
+
+ * modify it under the terms of the GNU General Public License
+
+ * as published by the Free Software Foundation; either version 2
+
+ * of the License, or (at your option) any later version. The Blender
+
+ * Foundation also sells licenses for use in proprietary software under
+
+ * the Blender License. See http://www.blender.org/BL/ for information
+
+ * about this.
+
+ *
+
+ * This program is distributed in the hope that it will be useful,
+
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+
+ * GNU General Public License for more details.
+
+ *
+
+ * You should have received a copy of the GNU General Public License
+
+ * along with this program; if not, write to the Free Software Foundation,
+
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ *
+
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+
+ * All rights reserved.
+
+ *
+
+ * The Original Code is: all of this file.
+
+ *
+
+ * Contributor(s): snailrose.
+
+ *
+
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+ */
+
+#ifndef _SCA_JOYSTICK_H_
+
+#define _SCA_JOYSTICK_H_
+
+
+
+#include "SCA_JoystickDefines.h"
+
+
+
+
+
+/*
+
+ * Basic Joystick class
+
+ */
+
+class SCA_Joystick
+
+{
+
+ class PrivateData;
+
+ PrivateData *m_private;
+
+ int m_joyindex;
+
+ /*!
+
+ * the number of avail joysticks
+
+ */
+
+ int m_numjoys;
+
+ /*
+
+ *support for 2 axes
+
+ */
+
+ int m_axis10,m_axis11;
+
+ int m_axis20,m_axis21;
+
+ /*
+
+ * Precision or range of the axes
+
+ */
+
+ int m_prec;
+
+ /*
+
+ * multiple axis values stored here
+
+ */
+
+ int m_axisnum;
+
+ int m_axisvalue;
+
+ /*
+
+ * max # of axes avail
+
+ */
+
+ /*disabled
+
+ int m_axismax;
+
+ */
+
+ /*
+
+ * button values stored here
+
+ */
+
+ int m_buttonnum;
+
+ /*
+
+ * max # of buttons avail
+
+ */
+
+ int m_buttonmax;
+
+ /*
+
+ * hat values stored here
+
+ */
+
+ int m_hatnum;
+
+ int m_hatdir;
+
+ /*
+
+ * max # of hats avail
+
+ disabled
+
+ int m_hatmax;
+
+ */
+
+ /* is the joystick initialized ?*/
+
+ bool m_isinit;
+
+
+
+ /* is triggered */
+
+ bool m_istrig;
+
+ /*
+
+ * Open the joystick
+
+ */
+
+ bool pCreateJoystickDevice(void);
+
+ /*
+
+ * Close the joystick
+
+ */
+
+ void pDestroyJoystickDevice(void);
+
+
+
+ /*
+
+ * event callbacks
+
+ */
+
+ void OnAxisMotion(void);
+
+ void OnHatMotion(void);
+
+ void OnButtonUp(void);
+
+ void OnButtonDown(void);
+
+ void OnNothing(void);
+
+ void OnBallMotion(void){}
+
+ /*
+
+ * fills the axis mnember values
+
+ */
+
+ void pFillAxes(void);
+
+
+
+ void pFillButtons(void);
+
+ /*
+
+ * returns m_axis10,m_axis11...
+
+ */
+
+ int pGetAxis(int axisnum, int udlr);
+
+ /*
+
+ * gets the current button
+
+ */
+
+ int pGetButtonPress(int button);
+
+ /*
+
+ * returns if no button is pressed
+
+ */
+
+ int pGetButtonRelease(int button);
+
+ /*
+
+ * gets the current hat direction
+
+ */
+
+ int pGetHat(int direction);
+
+
+
+public:
+
+ SCA_Joystick();
+
+ ~SCA_Joystick();
+
+
+
+ bool CreateJoystickDevice(void);
+
+ void DestroyJoystickDevice(void);
+
+ void HandleEvents();
+
+ /*
+
+ */
+
+ bool aUpAxisIsPositive(int axis);
+
+ bool aDownAxisIsPositive(int axis);
+
+ bool aLeftAxisIsPositive(int axis);
+
+ bool aRightAxisIsPositive(int axis);
+
+ bool aButtonPressIsPositive(int button);
+
+ bool aButtonReleaseIsPositive(int button);
+
+ bool aHatIsPositive(int dir);
+
+ /*
+
+ * precision is default '3200' which is overridden by input
+
+ */
+
+ void cSetPrecision(int val);
+
+
+
+ int GetAxis10(void){
+
+ return m_axis10;
+
+ }
+
+ int GetAxis11(void){
+
+ return m_axis11;
+
+ }
+
+ int GetAxis20(void){
+
+ return m_axis20;
+
+ }
+
+ int GetAxis21(void){
+
+ return m_axis21;
+
+ }
+
+ int GetButton(void){
+
+ return m_buttonnum;
+
+ }
+
+ int GetHat(void){
+
+ return m_hatdir;
+
+ }
+
+ int GetThreshold(void){
+
+ return m_prec;
+
+ }
+
+ bool IsTrig(void){
+
+ return m_istrig;
+
+ }
+
+
+
+ /*
+
+ * returns true if an event is being processed
+
+ */
+
+ bool GetJoyAxisMotion(void);
+
+ bool GetJoyButtonPress(void);
+
+ bool GetJoyButtonRelease(void);
+
+ bool GetJoyHatMotion(void);
+
+ /*
+
+ * returns the # of...
+
+ */
+
+ int GetNumberOfAxes(void);
+
+ int GetNumberOfButtons(void);
+
+ int GetNumberOfHats(void);
+
+
+
+};
+
+
+
+#endif
+
diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h
new file mode 100644
index 00000000000..c4ddd5b9c40
--- /dev/null
+++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h
@@ -0,0 +1,52 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): snailrose.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef _SCA_JOYSTICKDEFINES_H_
+#define _SCA_JOYSTICKDEFINES_H_
+
+#ifdef main
+#undef main
+#endif
+
+#ifndef _DEBUG
+#define echo(x)
+#else
+#include <iostream>
+#define echo(x) std::cout << x << std::endl;
+#endif
+
+/* function callbacks */
+#define HANDLE_AXISMOTION(fn) ((fn)(), 0L)
+#define HANDLE_HATMOTION(fn) ((fn)(), 0L)
+#define HANDLE_BUTTONUP(fn) ((fn)(), 0L)
+#define HANDLE_BUTTONDOWN(fn) ((fn)(), 0L)
+#define HANDLE_BALLMOTION(fn) ((fn)(), 0L)
+#define HANDLE_NOEVENT(fn) ((fn)(), 0L)
+
+#endif
diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp
new file mode 100644
index 00000000000..5fd8510d566
--- /dev/null
+++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp
@@ -0,0 +1,73 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): snailrose.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include <SDL.h>
+#include "SCA_Joystick.h"
+#include "SCA_JoystickPrivate.h"
+
+
+
+void SCA_Joystick::OnAxisMotion(void)
+{
+ pFillAxes();
+ m_axisnum = m_private->m_event.jaxis.axis;
+ m_axisvalue = m_private->m_event.jaxis.value;
+ m_istrig = 1;
+}
+
+
+void SCA_Joystick::OnHatMotion(void)
+{
+ m_hatdir = m_private->m_event.jhat.value;
+ m_hatnum = m_private->m_event.jhat.hat;
+ m_istrig = 1;
+}
+
+
+void SCA_Joystick::OnButtonUp(void)
+{
+ m_buttonnum = -2;
+}
+
+
+void SCA_Joystick::OnButtonDown(void)
+{
+ m_buttonmax = GetNumberOfButtons();
+ if(m_private->m_event.jbutton.button >= 1 || m_private->m_event.jbutton.button <= m_buttonmax)
+ {
+ m_istrig = 1;
+ m_buttonnum = m_private->m_event.jbutton.button;
+ }
+}
+
+
+void SCA_Joystick::OnNothing(void)
+{
+ m_istrig = 0;
+}
diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h b/source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h
new file mode 100644
index 00000000000..08435749cfe
--- /dev/null
+++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h
@@ -0,0 +1,52 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): snailrose.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef __SCA_JOYSTICKPRIVATE_H__
+#define __SCA_JOYSTICKPRIVATE_H__
+#include "SCA_Joystick.h"
+
+class SCA_Joystick::PrivateData
+{
+public:
+ /*
+ * SDL events structure
+ */
+ SDL_Event m_event;
+ /*
+ * The Joystick
+ */
+ SDL_Joystick* m_joystick;
+
+ PrivateData()
+ : m_joystick(NULL)
+ {
+ }
+};
+#endif
diff --git a/source/gameengine/GameLogic/Makefile b/source/gameengine/GameLogic/Makefile
new file mode 100644
index 00000000000..eab4e7faa7e
--- /dev/null
+++ b/source/gameengine/GameLogic/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 = logic
+SOURCEDIR = source/gameengine/gameengine/GameLogic
+DIR = $(OCGDIR)/gameengine/$(LIBNAME)
+DIRS = Joystick
+
+include nan_subdirs.mk
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../Expressions
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+CPPFLAGS += $(NAN_SDLCFLAGS)
+
+CPPFLAGS += -I../../kernel/gen_system
diff --git a/source/gameengine/GameLogic/SCA_ANDController.cpp b/source/gameengine/GameLogic/SCA_ANDController.cpp
new file mode 100644
index 00000000000..0daba011c71
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ANDController.cpp
@@ -0,0 +1,147 @@
+/**
+ * 'And' together all inputs
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_ANDController.h"
+#include "SCA_ISensor.h"
+#include "SCA_LogicManager.h"
+#include "BoolValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+SCA_ANDController::SCA_ANDController(SCA_IObject* gameobj,
+ PyTypeObject* T)
+ :
+ SCA_IController(gameobj,T)
+{
+}
+
+
+
+SCA_ANDController::~SCA_ANDController()
+{
+}
+
+
+
+void SCA_ANDController::Trigger(SCA_LogicManager* logicmgr)
+{
+
+ bool sensorresult = true;
+
+ for (vector<SCA_ISensor*>::const_iterator is=m_linkedsensors.begin();
+ !(is==m_linkedsensors.end());is++)
+ {
+ SCA_ISensor* sensor = *is;
+ if (!sensor->IsPositiveTrigger())
+ {
+ sensorresult = false;
+ break;
+ }
+ }
+
+ CValue* newevent = new CBoolValue(sensorresult);
+
+ for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin();
+ !(i==m_linkedactuators.end());i++)
+ {
+ SCA_IActuator* actua = *i;//m_linkedactuators.at(i);
+ logicmgr->AddActiveActuator(actua,newevent);
+ }
+
+ // every actuator that needs the event, has a it's own reference to it now so
+ // release it (so to be clear: if there is no actuator, it's deleted right now)
+ newevent->Release();
+
+}
+
+
+
+CValue* SCA_ANDController::GetReplica()
+{
+ CValue* replica = new SCA_ANDController(*this);
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject SCA_ANDController::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_ANDController",
+ sizeof(SCA_ANDController),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_ANDController::Parents[] = {
+ &SCA_ANDController::Type,
+ &SCA_IController::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef SCA_ANDController::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* SCA_ANDController::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IController);
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_ANDController.h b/source/gameengine/GameLogic/SCA_ANDController.h
new file mode 100644
index 00000000000..d32bfd2aa48
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ANDController.h
@@ -0,0 +1,59 @@
+/**
+ * SCA_ANDController.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 __KX_ANDCONTROLLER
+#define __KX_ANDCONTROLLER
+
+#include "SCA_IController.h"
+
+class SCA_ANDController : public SCA_IController
+{
+ Py_Header;
+ //virtual void Trigger(class SCA_LogicManager* logicmgr);
+public:
+ SCA_ANDController(SCA_IObject* gameobj,PyTypeObject* T=&Type);
+ virtual ~SCA_ANDController();
+ virtual CValue* GetReplica();
+ virtual void Trigger(SCA_LogicManager* logicmgr);
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+};
+
+#endif //__KX_ANDCONTROLLER
+
diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp b/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp
new file mode 100644
index 00000000000..c4b5b8197a7
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp
@@ -0,0 +1,69 @@
+/**
+ * Manager for 'always' events. Since always sensors can operate in pulse
+ * mode, they need to be activated.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_AlwaysEventManager.h"
+#include "SCA_LogicManager.h"
+#include <vector>
+#include "SCA_ISensor.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+using namespace std;
+
+SCA_AlwaysEventManager::SCA_AlwaysEventManager(class SCA_LogicManager* logicmgr)
+ : SCA_EventManager(ALWAYS_EVENTMGR),
+ m_logicmgr(logicmgr)
+{
+}
+
+
+
+void SCA_AlwaysEventManager::NextFrame()
+{
+ for (vector<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++)
+ {
+ SCA_ISensor* sensor = *i;
+ sensor->Activate(m_logicmgr, NULL);
+ }
+}
+
+
+
+void SCA_AlwaysEventManager::RegisterSensor(SCA_ISensor* sensor)
+{
+ m_sensors.push_back(sensor);
+}
diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.h b/source/gameengine/GameLogic/SCA_AlwaysEventManager.h
new file mode 100644
index 00000000000..bffd21da74c
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_AlwaysEventManager.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 __KX_ALWAYSEVENTMGR
+#define __KX_ALWAYSEVENTMGR
+#include "SCA_EventManager.h"
+#include <vector>
+
+using namespace std;
+class SCA_AlwaysEventManager : public SCA_EventManager
+{
+
+ class SCA_LogicManager* m_logicmgr;
+public:
+ SCA_AlwaysEventManager(class SCA_LogicManager* logicmgr);
+ virtual void NextFrame();
+ virtual void RegisterSensor(SCA_ISensor* sensor);
+
+
+};
+
+#endif //__KX_ALWAYSEVENTMGR
+
diff --git a/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp b/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp
new file mode 100644
index 00000000000..a0bb7311eb9
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp
@@ -0,0 +1,142 @@
+/**
+ * Always trigger
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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
+// This warning tells us about truncation of __long__ stl-generated names.
+// It can occasionally cause DevStudio to have internal compiler warnings.
+#pragma warning( disable : 4786 )
+#endif
+
+#include "SCA_AlwaysSensor.h"
+#include "SCA_LogicManager.h"
+#include "SCA_EventManager.h"
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+SCA_AlwaysSensor::SCA_AlwaysSensor(class SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ PyTypeObject* T)
+ : SCA_ISensor(gameobj,eventmgr, T)
+{
+ //SetDrawColor(255,0,0);
+ m_alwaysresult = true;
+}
+
+
+
+SCA_AlwaysSensor::~SCA_AlwaysSensor()
+{
+ /* intentionally empty */
+}
+
+
+
+CValue* SCA_AlwaysSensor::GetReplica()
+{
+ CValue* replica = new SCA_AlwaysSensor(*this);//m_float,GetName());
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+bool SCA_AlwaysSensor::IsPositiveTrigger()
+{
+ return (m_invert ? false : true);
+}
+
+
+
+bool SCA_AlwaysSensor::Evaluate(CValue* event)
+{
+ /* Nice! :) */
+ //return true;
+ /* even nicer ;) */
+ //return false;
+
+ /* nicest ! */
+ bool result = m_alwaysresult;
+ m_alwaysresult = false;
+ return result;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject SCA_AlwaysSensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_AlwaysSensor",
+ sizeof(SCA_AlwaysSensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_AlwaysSensor::Parents[] = {
+ &SCA_AlwaysSensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef SCA_AlwaysSensor::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* SCA_AlwaysSensor::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_ISensor);
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_AlwaysSensor.h b/source/gameengine/GameLogic/SCA_AlwaysSensor.h
new file mode 100644
index 00000000000..456516fa989
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_AlwaysSensor.h
@@ -0,0 +1,62 @@
+/**
+ * SCA_AlwaysSensor.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 __KX_ALWAYSSENSOR
+#define __KX_ALWAYSSENSOR
+#include "SCA_ISensor.h"
+
+class SCA_AlwaysSensor : public SCA_ISensor
+{
+ Py_Header;
+ bool m_alwaysresult;
+public:
+ SCA_AlwaysSensor(class SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ PyTypeObject* T =&Type);
+ virtual ~SCA_AlwaysSensor();
+ virtual CValue* GetReplica();
+ virtual bool Evaluate(CValue* event);
+ virtual bool IsPositiveTrigger();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+
+};
+
+#endif //__KX_ALWAYSSENSOR
+
diff --git a/source/gameengine/GameLogic/SCA_EventManager.cpp b/source/gameengine/GameLogic/SCA_EventManager.cpp
new file mode 100644
index 00000000000..9c39b332d40
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_EventManager.cpp
@@ -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 *****
+ */
+
+#include <assert.h>
+#include "SCA_EventManager.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+SCA_EventManager::SCA_EventManager(EVENT_MANAGER_TYPE mgrtype)
+ :m_mgrtype(mgrtype)
+{
+}
+
+
+
+SCA_EventManager::~SCA_EventManager()
+{
+}
+
+
+
+void SCA_EventManager::RemoveSensor(class SCA_ISensor* sensor)
+{
+ std::vector<SCA_ISensor*>::iterator i =
+ std::find(m_sensors.begin(), m_sensors.end(), sensor);
+ if (!(i == m_sensors.end()))
+ {
+ std::swap(*i, m_sensors.back());
+ m_sensors.pop_back();
+ }
+}
+
+void SCA_EventManager::NextFrame(double curtime, double fixedtime)
+{
+ NextFrame();
+}
+
+void SCA_EventManager::NextFrame()
+{
+ assert(false); // && "Event managers should override a NextFrame method");
+}
+
+void SCA_EventManager::EndFrame()
+{
+}
+
+
+
+int SCA_EventManager::GetType()
+{
+ return (int) m_mgrtype;
+}
diff --git a/source/gameengine/GameLogic/SCA_EventManager.h b/source/gameengine/GameLogic/SCA_EventManager.h
new file mode 100644
index 00000000000..e15e19b239b
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_EventManager.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 *****
+ */
+#ifndef __KX_EVENTMANAGER
+#define __KX_EVENTMANAGER
+
+#include <vector>
+#include <algorithm>
+
+class SCA_EventManager
+{
+protected:
+ std::vector <class SCA_ISensor*> m_sensors;
+
+public:
+ enum EVENT_MANAGER_TYPE {
+ KEYBOARD_EVENTMGR = 0,
+ MOUSE_EVENTMGR,
+ ALWAYS_EVENTMGR,
+ TOUCH_EVENTMGR,
+ PROPERTY_EVENTMGR,
+ TIME_EVENTMGR,
+ RANDOM_EVENTMGR,
+ RAY_EVENTMGR,
+ RADAR_EVENTMGR,
+ NETWORK_EVENTMGR,
+ JOY_EVENTMGR
+ };
+
+ SCA_EventManager(EVENT_MANAGER_TYPE mgrtype);
+ virtual ~SCA_EventManager();
+
+ virtual void RemoveSensor(class SCA_ISensor* sensor);
+ virtual void NextFrame(double curtime, double fixedtime);
+ virtual void NextFrame();
+ virtual void EndFrame();
+ virtual void RegisterSensor(class SCA_ISensor* sensor)=0;
+ int GetType();
+
+protected:
+ EVENT_MANAGER_TYPE m_mgrtype;
+};
+
+#endif
+
diff --git a/source/gameengine/GameLogic/SCA_ExpressionController.cpp b/source/gameengine/GameLogic/SCA_ExpressionController.cpp
new file mode 100644
index 00000000000..36e83f2a98c
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ExpressionController.cpp
@@ -0,0 +1,164 @@
+/**
+ * 'Expression Controller enables to calculate an expression that wires inputs to output
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_ExpressionController.h"
+#include "SCA_ISensor.h"
+#include "SCA_LogicManager.h"
+#include "BoolValue.h"
+#include "InputParser.h"
+#include "MT_Transform.h" // for fuzzyZero
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+SCA_ExpressionController::SCA_ExpressionController(SCA_IObject* gameobj,
+ const STR_String& exprtext,
+ PyTypeObject* T)
+ :SCA_IController(gameobj,T),
+ m_exprText(exprtext)
+{
+}
+
+
+
+SCA_ExpressionController::~SCA_ExpressionController()
+{
+}
+
+
+
+CValue* SCA_ExpressionController::GetReplica()
+{
+ SCA_ExpressionController* replica = new SCA_ExpressionController(*this);
+ replica->m_exprText = m_exprText;
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+void SCA_ExpressionController::Trigger(SCA_LogicManager* logicmgr)
+{
+
+ bool expressionresult = false;
+
+ CParser parser;
+ parser.SetContext(this->AddRef());
+ CExpression* expr = parser.ProcessText(m_exprText);
+ if (expr)
+ {
+ CValue* value = expr->Calculate();
+ if (value)
+ {
+ if (value->IsError())
+ {
+ printf(value->GetText());
+ } else
+ {
+ float num = value->GetNumber();
+ expressionresult = !MT_fuzzyZero(num);
+ }
+ value->Release();
+
+ }
+ expr->Release();
+ }
+
+ /*
+
+ for (vector<SCA_ISensor*>::const_iterator is=m_linkedsensors.begin();
+ !(is==m_linkedsensors.end());is++)
+ {
+ SCA_ISensor* sensor = *is;
+ if (!sensor->IsPositiveTrigger())
+ {
+ sensorresult = false;
+ break;
+ }
+ }
+
+ */
+
+ CValue* newevent = new CBoolValue(expressionresult);
+
+ for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin();
+ !(i==m_linkedactuators.end());i++)
+ {
+ SCA_IActuator* actua = *i;
+ logicmgr->AddActiveActuator(actua,newevent);
+ }
+ //printf("expr %d.",expressionresult);
+ // every actuator that needs the event, has a it's own reference to it now so
+ // release it (so to be clear: if there is no actuator, it's deleted right now)
+ newevent->Release();
+}
+
+
+
+CValue* SCA_ExpressionController::FindIdentifier(const STR_String& identifiername)
+{
+
+ CValue* identifierval = NULL;
+
+ for (vector<SCA_ISensor*>::const_iterator is=m_linkedsensors.begin();
+ !(is==m_linkedsensors.end());is++)
+ {
+ SCA_ISensor* sensor = *is;
+ if (sensor->GetName() == identifiername)
+ {
+ identifierval = new CBoolValue(sensor->IsPositiveTrigger());
+ //identifierval = sensor->AddRef();
+ }
+
+ //if (!sensor->IsPositiveTrigger())
+ //{
+ // sensorresult = false;
+ // break;
+ //}
+ }
+
+ if (identifierval)
+ return identifierval;
+
+ return GetParent()->FindIdentifier(identifiername);
+
+}
diff --git a/source/gameengine/GameLogic/SCA_ExpressionController.h b/source/gameengine/GameLogic/SCA_ExpressionController.h
new file mode 100644
index 00000000000..e77f2b9938b
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ExpressionController.h
@@ -0,0 +1,64 @@
+/**
+ * KX_EXPRESSIONController.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 __KX_EXPRESSIONCONTROLLER
+#define __KX_EXPRESSIONCONTROLLER
+
+#include "SCA_IController.h"
+
+class SCA_ExpressionController : public SCA_IController
+{
+// Py_Header;
+ STR_String m_exprText;
+
+public:
+ SCA_ExpressionController(SCA_IObject* gameobj,
+ const STR_String& exprtext,
+ PyTypeObject* T=&Type );
+
+ virtual ~SCA_ExpressionController();
+ virtual CValue* GetReplica();
+ virtual void Trigger(SCA_LogicManager* logicmgr);
+ virtual CValue* FindIdentifier(const STR_String& identifiername);
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+// virtual PyObject* _getattr(const STR_String& attr);
+
+};
+
+#endif //__KX_EXPRESSIONCONTROLLER
+
diff --git a/source/gameengine/GameLogic/SCA_IActuator.cpp b/source/gameengine/GameLogic/SCA_IActuator.cpp
new file mode 100644
index 00000000000..322936c7819
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_IActuator.cpp
@@ -0,0 +1,114 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_IActuator.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+using namespace std;
+
+SCA_IActuator::SCA_IActuator(SCA_IObject* gameobj,
+ PyTypeObject* T) :
+ SCA_ILogicBrick(gameobj,T)
+{
+ // nothing to do
+}
+
+
+
+void SCA_IActuator::AddEvent(CValue* event)
+{
+ m_events.push_back(event);
+}
+
+
+
+void SCA_IActuator::RemoveAllEvents()
+{ // remove event queue!
+ for (vector<CValue*>::iterator i=m_events.begin(); !(i==m_events.end());i++)
+ {
+ (*i)->Release();
+ }
+ m_events.clear();
+}
+
+
+
+
+
+bool SCA_IActuator::IsNegativeEvent() const
+{
+ bool bPositiveEvent(false);
+ bool bNegativeEvent(false);
+
+ for (vector<CValue*>::const_iterator i=m_events.begin(); i!=m_events.end();++i)
+ {
+ if ((*i)->GetNumber() == 0.0f)
+ {
+ bNegativeEvent = true;
+ } else {
+ bPositiveEvent = true;
+ }
+ }
+
+ // if at least 1 positive event, return false
+
+ return !bPositiveEvent && bNegativeEvent;
+}
+
+bool SCA_IActuator::Update(double curtime, bool frame)
+{
+ if (frame)
+ return Update();
+
+ return true;
+}
+
+bool SCA_IActuator::Update()
+{
+ assert(false && "Actuators should override an Update method.");
+ return false;
+}
+
+void SCA_IActuator::ProcessReplica()
+{
+ m_events.clear();
+}
+
+
+
+SCA_IActuator::~SCA_IActuator()
+{
+ RemoveAllEvents();
+}
+
diff --git a/source/gameengine/GameLogic/SCA_IActuator.h b/source/gameengine/GameLogic/SCA_IActuator.h
new file mode 100644
index 00000000000..e58ac74dacf
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_IActuator.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 __KX_IACTUATOR
+#define __KX_IACTUATOR
+
+#include "SCA_ILogicBrick.h"
+#include <vector>
+
+class SCA_IActuator : public SCA_ILogicBrick
+{
+protected:
+ std::vector<CValue*> m_events;
+ void RemoveAllEvents();
+
+public:
+ /**
+ * This class also inherits the default copy constructors
+ */
+
+ SCA_IActuator(SCA_IObject* gameobj,
+ PyTypeObject* T =&Type);
+
+ /**
+ * Update(...)
+ * Update the actuator based upon the events received since
+ * the last call to Update, the current time and deltatime the
+ * time elapsed in this frame ?
+ * It is the responsibility of concrete Actuators to clear
+ * their event's. This is usually done in the Update() method via
+ * a call to RemoveAllEvents()
+ */
+
+
+ virtual bool Update(double curtime, bool frame);
+ virtual bool Update();
+
+ /**
+ * Add an event to an actuator.
+ */
+ void AddEvent(CValue* event);
+ virtual void ProcessReplica();
+
+ /**
+ * Return true iff all the current events
+ * are negative. The definition of negative event is
+ * not immediately clear. But usually refers to key-up events
+ * or events where no action is required.
+ */
+ bool IsNegativeEvent() const;
+ virtual ~SCA_IActuator();
+};
+
+#endif //__KX_IACTUATOR
+
diff --git a/source/gameengine/GameLogic/SCA_IController.cpp b/source/gameengine/GameLogic/SCA_IController.cpp
new file mode 100644
index 00000000000..bd70e4aa44b
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_IController.cpp
@@ -0,0 +1,123 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_IController.h"
+#include "SCA_LogicManager.h"
+#include "SCA_IActuator.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+SCA_IController::SCA_IController(SCA_IObject* gameobj,
+ PyTypeObject* T)
+ :
+ SCA_ILogicBrick(gameobj,T)
+{
+}
+
+
+
+SCA_IController::~SCA_IController()
+{
+}
+
+
+
+const std::vector<class SCA_ISensor*>& SCA_IController::GetLinkedSensors()
+{
+ return m_linkedsensors;
+}
+
+
+
+const std::vector<class SCA_IActuator*>& SCA_IController::GetLinkedActuators()
+{
+ return m_linkedactuators;
+}
+
+
+
+void SCA_IController::UnlinkAllSensors()
+{
+ m_linkedsensors.clear();
+}
+
+
+
+void SCA_IController::UnlinkAllActuators()
+{
+ m_linkedactuators.clear();
+}
+
+
+
+/*
+void SCA_IController::Trigger(SCA_LogicManager* logicmgr)
+{
+ //for (int i=0;i<m_linkedactuators.size();i++)
+ for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin();
+ !(i==m_linkedactuators.end());i++)
+ {
+ SCA_IActuator* actua = *i;//m_linkedactuators.at(i);
+
+ logicmgr->AddActiveActuator(actua);
+ }
+
+}
+*/
+
+void SCA_IController::LinkToActuator(SCA_IActuator* actua)
+{
+ m_linkedactuators.push_back(actua);
+}
+
+void SCA_IController::UnlinkActuator(class SCA_IActuator* actua)
+{
+ std::vector<class SCA_IActuator*>::iterator actit;
+ std::vector<class SCA_IActuator*>::iterator actfound = m_linkedactuators.end();
+ for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit)
+ {
+ if ((*actit) == actua)
+ actfound = actit;
+
+ }
+ if (!(actfound==m_linkedactuators.end()))
+ {
+ m_linkedactuators.erase(actfound);
+ }
+
+}
+
+void SCA_IController::LinkToSensor(SCA_ISensor* sensor)
+{
+ m_linkedsensors.push_back(sensor);
+}
diff --git a/source/gameengine/GameLogic/SCA_IController.h b/source/gameengine/GameLogic/SCA_IController.h
new file mode 100644
index 00000000000..31bbca2480a
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_IController.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 __KX_ICONTROLLER
+#define __KX_ICONTROLLER
+
+#include "SCA_ILogicBrick.h"
+
+class SCA_IController : public SCA_ILogicBrick
+{
+protected:
+ std::vector<class SCA_ISensor*> m_linkedsensors;
+ std::vector<class SCA_IActuator*> m_linkedactuators;
+public:
+ SCA_IController(SCA_IObject* gameobj,PyTypeObject* T);
+ virtual ~SCA_IController();
+ virtual void Trigger(class SCA_LogicManager* logicmgr)=0;
+ void LinkToSensor(SCA_ISensor* sensor);
+ void LinkToActuator(SCA_IActuator*);
+ const std::vector<class SCA_ISensor*>& GetLinkedSensors();
+ const std::vector<class SCA_IActuator*>& GetLinkedActuators();
+ void UnlinkAllSensors();
+ void UnlinkAllActuators();
+ void UnlinkActuator(class SCA_IActuator* actua);
+
+
+};
+
+#endif
+
diff --git a/source/gameengine/GameLogic/SCA_IInputDevice.cpp b/source/gameengine/GameLogic/SCA_IInputDevice.cpp
new file mode 100644
index 00000000000..c6858cdb75a
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_IInputDevice.cpp
@@ -0,0 +1,138 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 <assert.h>
+#include "SCA_IInputDevice.h"
+
+SCA_IInputDevice::SCA_IInputDevice()
+ :
+ m_currentTable(0)
+{
+ ClearStatusTable(0);
+ ClearStatusTable(1);
+}
+
+
+
+SCA_IInputDevice::~SCA_IInputDevice()
+{
+}
+
+void SCA_IInputDevice::HookEscape()
+{
+ assert(false && "This device does not support hooking escape.");
+}
+
+void SCA_IInputDevice::ClearStatusTable(int tableid)
+{
+ for (int i=0;i<SCA_IInputDevice::KX_MAX_KEYS;i++)
+ m_eventStatusTables[tableid][i]=SCA_InputEvent(SCA_InputEvent::KX_NO_INPUTSTATUS,0);
+}
+
+
+
+const SCA_InputEvent& SCA_IInputDevice::GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode)
+{
+ // cerr << "SCA_IInputDevice::GetEventValue" << endl;
+ return m_eventStatusTables[m_currentTable][inputcode];
+}
+
+
+
+int SCA_IInputDevice::GetNumActiveEvents()
+{
+ int num = 0;
+
+ // cerr << "SCA_IInputDevice::GetNumActiveEvents" << endl;
+
+ for (int i=0;i<SCA_IInputDevice::KX_MAX_KEYS;i++)
+ {
+ const SCA_InputEvent& event = m_eventStatusTables[m_currentTable][i];
+ if ((event.m_status == SCA_InputEvent::KX_JUSTACTIVATED)
+ || (event.m_status == SCA_InputEvent::KX_ACTIVE))
+ num++;
+ }
+
+ return num;
+}
+
+
+
+int SCA_IInputDevice::GetNumJustEvents()
+{
+ int num = 0;
+
+ // cerr << "SCA_IInputDevice::GetNumJustEvents" << endl;
+
+ for (int i=0;i<SCA_IInputDevice::KX_MAX_KEYS;i++)
+ {
+ const SCA_InputEvent& event = m_eventStatusTables[m_currentTable][i];
+ if ((event.m_status == SCA_InputEvent::KX_JUSTACTIVATED)
+ || (event.m_status == SCA_InputEvent::KX_JUSTRELEASED))
+ num++;
+ }
+
+ return num;
+}
+
+
+
+void SCA_IInputDevice::NextFrame()
+{
+ m_currentTable = 1 - m_currentTable;
+
+ // cerr << "SCA_IInputDevice::NextFrame " << GetNumActiveEvents() << endl;
+
+ for (int i=0;i<SCA_IInputDevice::KX_MAX_KEYS;i++)
+ {
+ switch (m_eventStatusTables[1 - m_currentTable][i].m_status)
+ {
+ case SCA_InputEvent::KX_NO_INPUTSTATUS:
+ m_eventStatusTables[m_currentTable][i]
+ = SCA_InputEvent(SCA_InputEvent::KX_NO_INPUTSTATUS, 1);
+ break;
+ case SCA_InputEvent::KX_JUSTACTIVATED:
+ m_eventStatusTables[m_currentTable][i]
+ = SCA_InputEvent(SCA_InputEvent::KX_ACTIVE, 1);
+ break;
+ case SCA_InputEvent::KX_ACTIVE:
+ m_eventStatusTables[m_currentTable][i]
+ = SCA_InputEvent(SCA_InputEvent::KX_ACTIVE, 1);
+ break;
+ case SCA_InputEvent::KX_JUSTRELEASED:
+ m_eventStatusTables[m_currentTable][i]
+ = SCA_InputEvent(SCA_InputEvent::KX_NO_INPUTSTATUS, 1);
+ break;
+ default:
+ ; /* error */
+ }
+ }
+}
diff --git a/source/gameengine/GameLogic/SCA_IInputDevice.h b/source/gameengine/GameLogic/SCA_IInputDevice.h
new file mode 100644
index 00000000000..6dee608a568
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_IInputDevice.h
@@ -0,0 +1,312 @@
+/**
+ * Interface for input devices. The defines for keyboard/system/mouse events
+ * here are for internal use in the KX module.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 KX_INPUTDEVICE_H
+#define KX_INPUTDEVICE_H
+
+class SCA_InputEvent
+{
+
+public:
+ enum SCA_EnumInputs {
+
+ KX_NO_INPUTSTATUS = 0,
+ KX_JUSTACTIVATED,
+ KX_ACTIVE,
+ KX_JUSTRELEASED,
+ KX_MAX_INPUTSTATUS
+ };
+
+ SCA_InputEvent(SCA_EnumInputs status=KX_NO_INPUTSTATUS,int eventval=0)
+ : m_status(status),
+ m_eventval(eventval)
+ {
+
+ }
+
+ SCA_EnumInputs m_status;
+ int m_eventval;
+};
+
+class SCA_IInputDevice
+{
+
+
+public:
+
+ SCA_IInputDevice();
+ virtual ~SCA_IInputDevice();
+
+ enum KX_EnumInputs {
+
+ KX_NOKEY = 0,
+
+ // TIMERS
+
+ KX_TIMER0,
+ KX_TIMER1,
+ KX_TIMER2,
+ KX_TIMER3,
+
+ // SYSTEM
+
+ /* Moved to avoid clashes with KX_RETKEY */
+ KX_KEYBD,
+ KX_RAWKEYBD,
+ KX_REDRAW,
+ KX_INPUTCHANGE,
+ KX_QFULL,
+ KX_WINFREEZE,
+ KX_WINTHAW,
+ /* thaw is 11 */
+
+ /* move past retkey*/
+ KX_WINCLOSE = 14,
+ KX_WINQUIT,
+ KX_Q_FIRSTTIME,
+ /* sequence ends on 16 */
+
+ // standard keyboard
+
+ /* Because of the above preamble, KX_BEGINKEY is 15 ! This
+ * means that KX_RETKEY on 13d (0Dh)) will double up with
+ * KX_WINQUIT! Why is it 13? Because ascii 13d is Ctrl-M aka
+ * CR! Its little brother, LF has 10d (0Ah). This is
+ * dangerous, since the keyboards start scanning at
+ * KX_BEGINKEY. I think the keyboard system should push its
+ * key events instead of demanding the user to poll the
+ * table... But that's for another time... The fix for now is
+ * to move the above system events into a 'safe' (ie. unused)
+ * range. I am loathe to move it away from this 'magical'
+ * coincidence.. it's probably exploited somewhere. I hope the
+ * close and quit events don't mess up 'normal' kb code
+ * scanning.
+ * */
+ KX_BEGINKEY = 12,
+
+ KX_RETKEY = 13,
+ KX_SPACEKEY = 32,
+ KX_PADASTERKEY = 42,
+ KX_COMMAKEY = 44,
+ KX_MINUSKEY = 45,
+ KX_PERIODKEY = 46,
+ KX_ZEROKEY = 48,
+
+ KX_ONEKEY, // =49
+ KX_TWOKEY,
+ KX_THREEKEY,
+ KX_FOURKEY,
+ KX_FIVEKEY,
+ KX_SIXKEY,
+ KX_SEVENKEY,
+ KX_EIGHTKEY,
+ KX_NINEKEY, // = 57
+
+ KX_AKEY = 97,
+ KX_BKEY,
+ KX_CKEY,
+ KX_DKEY,
+ KX_EKEY,
+ KX_FKEY,
+ KX_GKEY,
+ KX_HKEY,
+ KX_IKEY,
+ KX_JKEY,
+ KX_KKEY,
+ KX_LKEY,
+ KX_MKEY,
+ KX_NKEY, // =110
+ KX_OKEY,
+ KX_PKEY,
+ KX_QKEY,
+ KX_RKEY,
+ KX_SKEY,
+ KX_TKEY,
+ KX_UKEY,
+ KX_VKEY,
+ KX_WKEY,
+ KX_XKEY, // =120
+ KX_YKEY,
+ KX_ZKEY, // =122
+
+
+
+ KX_CAPSLOCKKEY, // 123
+
+ KX_LEFTCTRLKEY, // 124
+ KX_LEFTALTKEY,
+ KX_RIGHTALTKEY,
+ KX_RIGHTCTRLKEY,
+ KX_RIGHTSHIFTKEY,
+ KX_LEFTSHIFTKEY,// 129
+
+ KX_ESCKEY, // 130
+ KX_TABKEY, //131
+
+
+ KX_LINEFEEDKEY, // 132
+ KX_BACKSPACEKEY,
+ KX_DELKEY,
+ KX_SEMICOLONKEY, // 135
+
+
+ KX_QUOTEKEY, //136
+ KX_ACCENTGRAVEKEY, //137
+
+ KX_SLASHKEY, //138
+ KX_BACKSLASHKEY,
+ KX_EQUALKEY,
+ KX_LEFTBRACKETKEY,
+ KX_RIGHTBRACKETKEY, // 142
+
+ KX_LEFTARROWKEY, // 145
+ KX_DOWNARROWKEY,
+ KX_RIGHTARROWKEY,
+ KX_UPARROWKEY, // 148
+
+ KX_PAD2 ,
+ KX_PAD4 ,
+ KX_PAD6 ,
+ KX_PAD8 ,
+
+ KX_PAD1 ,
+ KX_PAD3 ,
+ KX_PAD5 ,
+ KX_PAD7 ,
+ KX_PAD9 ,
+
+ KX_PADPERIOD,
+ KX_PADSLASHKEY,
+
+
+
+ KX_PAD0 ,
+ KX_PADMINUS,
+ KX_PADENTER,
+ KX_PADPLUSKEY,
+
+
+ KX_F1KEY ,
+ KX_F2KEY ,
+ KX_F3KEY ,
+ KX_F4KEY ,
+ KX_F5KEY ,
+ KX_F6KEY ,
+ KX_F7KEY ,
+ KX_F8KEY ,
+ KX_F9KEY ,
+ KX_F10KEY,
+ KX_F11KEY,
+ KX_F12KEY,
+
+ KX_PAUSEKEY,
+ KX_INSERTKEY,
+ KX_HOMEKEY ,
+ KX_PAGEUPKEY,
+ KX_PAGEDOWNKEY,
+ KX_ENDKEY,
+
+ // MOUSE
+ KX_BEGINMOUSE,
+
+ KX_BEGINMOUSEBUTTONS,
+
+ KX_LEFTMOUSE,
+ KX_MIDDLEMOUSE,
+ KX_RIGHTMOUSE,
+
+ KX_ENDMOUSEBUTTONS,
+
+ KX_WHEELUPMOUSE,
+ KX_WHEELDOWNMOUSE,
+
+ KX_MOUSEX,
+ KX_MOUSEY,
+
+ KX_ENDMOUSE,
+
+
+
+ KX_MAX_KEYS
+
+ } ; // enum
+
+
+protected:
+ /**
+ m_eventStatusTables are two tables that contain current and previous
+ status of all events
+ */
+
+ SCA_InputEvent m_eventStatusTables[2][SCA_IInputDevice::KX_MAX_KEYS];
+ /**
+ m_currentTable is index for m_keyStatusTable that toggle between 0 or 1
+ */
+ int m_currentTable;
+ void ClearStatusTable(int tableid);
+
+public:
+ virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode)=0;
+ virtual const SCA_InputEvent& GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode);
+
+ /**
+ * Count active events(active and just_activated)
+ */
+ virtual int GetNumActiveEvents();
+
+ /**
+ * Get the number of ramping events (just_activated, just_released)
+ */
+ virtual int GetNumJustEvents();
+
+ virtual void HookEscape();
+
+ /* Next frame: we calculate the new key states. This goes as follows:
+ *
+ * KX_NO_INPUTSTATUS -> KX_NO_INPUTSTATUS
+ * KX_JUSTACTIVATED -> KX_ACTIVE
+ * KX_ACTIVE -> KX_ACTIVE
+ * KX_JUSTRELEASED -> KX_NO_INPUTSTATUS
+ *
+ * Getting new events provides the
+ * KX_NO_INPUTSTATUS->KX_JUSTACTIVATED and
+ * KX_ACTIVE->KX_JUSTRELEASED transitions.
+ */
+ virtual void NextFrame();
+
+};
+
+#endif //KX_INPUTDEVICE_H
+
diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp
new file mode 100644
index 00000000000..1780458ba45
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp
@@ -0,0 +1,324 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_ILogicBrick.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+SCA_LogicManager* SCA_ILogicBrick::m_sCurrentLogicManager = NULL;
+
+SCA_ILogicBrick::SCA_ILogicBrick(SCA_IObject* gameobj,
+ PyTypeObject* T)
+ :
+ CValue(T),
+ m_gameobj(gameobj),
+ m_Execute_Priority(0),
+ m_Execute_Ueber_Priority(0),
+ m_bActive(false),
+ m_eventval(0)
+{
+ m_text = "KX_LogicBrick";
+}
+
+
+
+SCA_ILogicBrick::~SCA_ILogicBrick()
+{
+ RemoveEvent();
+}
+
+
+
+void SCA_ILogicBrick::SetExecutePriority(int execute_Priority)
+{
+ m_Execute_Priority = execute_Priority;
+}
+
+
+
+void SCA_ILogicBrick::SetUeberExecutePriority(int execute_Priority)
+{
+ m_Execute_Ueber_Priority = execute_Priority;
+}
+
+
+
+SCA_IObject* SCA_ILogicBrick::GetParent()
+{
+ return m_gameobj;
+}
+
+
+
+void SCA_ILogicBrick::ReParent(SCA_IObject* parent)
+{
+ m_gameobj = parent;
+}
+
+
+
+CValue* SCA_ILogicBrick::Calc(VALUE_OPERATOR op, CValue *val)
+{
+ CValue* temp = new CBoolValue(false,"");
+ CValue* result = temp->Calc(op,val);
+ temp->Release();
+
+ return result;
+}
+
+
+
+CValue* SCA_ILogicBrick::CalcFinal(VALUE_DATA_TYPE dtype,
+ VALUE_OPERATOR op,
+ CValue *val)
+{
+ // same as bool implementation, so...
+ CValue* temp = new CBoolValue(false,"");
+ CValue* result = temp->CalcFinal(dtype,op,val);
+ temp->Release();
+
+ return result;
+}
+
+
+
+const STR_String& SCA_ILogicBrick::GetText()
+{
+ if (m_name.Length())
+ return m_name;
+
+ return m_text;
+}
+
+
+
+float SCA_ILogicBrick::GetNumber()
+{
+ return -1;
+}
+
+
+
+STR_String SCA_ILogicBrick::GetName()
+{
+ return m_name;
+}
+
+
+
+void SCA_ILogicBrick::SetName(STR_String name)
+{
+ m_name = name;
+}
+
+
+
+void SCA_ILogicBrick::ReplicaSetName(STR_String name)
+{
+ m_name = name;
+}
+
+
+
+bool SCA_ILogicBrick::IsActive()
+{
+ return m_bActive;
+}
+
+
+
+bool SCA_ILogicBrick::LessComparedTo(SCA_ILogicBrick* other)
+{
+ return (this->m_Execute_Ueber_Priority < other->m_Execute_Ueber_Priority)
+ || ((this->m_Execute_Ueber_Priority == other->m_Execute_Ueber_Priority) &&
+ (this->m_Execute_Priority < other->m_Execute_Priority));
+}
+
+
+
+void SCA_ILogicBrick::SetActive(bool active)
+{
+ m_bActive=active;
+ if (active)
+ {
+ //m_gameobj->SetDebugColor(GetDrawColor());
+ } else
+ {
+ //m_gameobj->ResetDebugColor();
+ }
+}
+
+
+
+void SCA_ILogicBrick::RegisterEvent(CValue* eventval)
+{
+ if (m_eventval)
+ m_eventval->Release();
+
+ m_eventval = eventval->AddRef();
+}
+
+
+void SCA_ILogicBrick::RemoveEvent()
+{
+ if (m_eventval)
+ {
+ m_eventval->Release();
+ m_eventval = NULL;
+ }
+}
+
+
+
+CValue* SCA_ILogicBrick::GetEvent()
+{
+ if (m_eventval)
+ {
+ return m_eventval->AddRef();
+ }
+
+ return NULL;
+}
+
+
+
+
+/* python stuff */
+
+PyTypeObject SCA_ILogicBrick::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_ILogicBrick",
+ sizeof(SCA_ILogicBrick),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+
+PyParentObject SCA_ILogicBrick::Parents[] = {
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+PyMethodDef SCA_ILogicBrick::Methods[] = {
+ {"getOwner", (PyCFunction) SCA_ILogicBrick::sPyGetOwner, METH_VARARGS},
+ {"getExecutePriority", (PyCFunction) SCA_ILogicBrick::sPySetExecutePriority, METH_VARARGS},
+ {"setExecutePriority", (PyCFunction) SCA_ILogicBrick::sPySetExecutePriority, METH_VARARGS},
+ {NULL,NULL} //Sentinel
+};
+
+
+
+PyObject*
+SCA_ILogicBrick::_getattr(const STR_String& attr)
+{
+ _getattr_up(CValue);
+}
+
+
+
+PyObject* SCA_ILogicBrick::PyGetOwner(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ CValue* parent = GetParent();
+ if (parent)
+ {
+ parent->AddRef();
+ return parent;
+ }
+
+ printf("ERROR: Python scriptblock without owner\n");
+ Py_INCREF(Py_None);
+ return Py_None;//Int_FromLong(IsPositiveTrigger());
+}
+
+
+
+PyObject* SCA_ILogicBrick::PySetExecutePriority(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ int priority=0;
+
+ if (!PyArg_ParseTuple(args, "i", &priority)) {
+ return NULL;
+ }
+
+ m_Execute_Ueber_Priority = priority;
+
+ Py_Return;
+}
+
+
+
+PyObject* SCA_ILogicBrick::PyGetExecutePriority(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyInt_FromLong(m_Execute_Ueber_Priority);
+}
+
+
+
+/* Conversions for making life better. */
+bool SCA_ILogicBrick::PyArgToBool(int boolArg)
+{
+ if (boolArg) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+
+PyObject* SCA_ILogicBrick::BoolToPyArg(bool boolarg)
+{
+ return PyInt_FromLong(boolarg? KX_TRUE: KX_FALSE);
+}
diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.h b/source/gameengine/GameLogic/SCA_ILogicBrick.h
new file mode 100644
index 00000000000..588c5ca7aba
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ILogicBrick.h
@@ -0,0 +1,112 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_ILOGICBRICK
+#define __KX_ILOGICBRICK
+
+#include "Value.h"
+#include "SCA_IObject.h"
+#include "BoolValue.h"
+
+class SCA_ILogicBrick : public CValue
+{
+ Py_Header;
+protected:
+ SCA_IObject* m_gameobj;
+ int m_Execute_Priority;
+ int m_Execute_Ueber_Priority;
+
+ bool m_bActive;
+ CValue* m_eventval;
+ STR_String m_text;
+ STR_String m_name;
+ //unsigned long m_drawcolor;
+ void RegisterEvent(CValue* eventval);
+ void RemoveEvent();
+ CValue* GetEvent();
+
+public:
+ SCA_ILogicBrick(SCA_IObject* gameobj,PyTypeObject* T );
+ virtual ~SCA_ILogicBrick();
+
+ void SetExecutePriority(int execute_Priority);
+ void SetUeberExecutePriority(int execute_Priority);
+
+ SCA_IObject* GetParent();
+ virtual void ReParent(SCA_IObject* parent);
+
+ // act as a BoolValue (with value IsPositiveTrigger)
+ virtual CValue* Calc(VALUE_OPERATOR op, CValue *val);
+ virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+
+ virtual const STR_String & GetText();
+ virtual float GetNumber();
+ virtual STR_String GetName();
+ virtual void SetName(STR_String name);
+ virtual void ReplicaSetName(STR_String name);
+
+ bool IsActive();
+ void SetActive(bool active) ;
+
+ virtual bool LessComparedTo(SCA_ILogicBrick* other);
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ static class SCA_LogicManager* m_sCurrentLogicManager;
+
+
+ // python methods
+
+ KX_PYMETHOD(SCA_ILogicBrick,GetOwner);
+ KX_PYMETHOD(SCA_ILogicBrick,SetExecutePriority);
+ KX_PYMETHOD(SCA_ILogicBrick,GetExecutePriority);
+
+ enum KX_BOOL_TYPE {
+ KX_BOOL_NODEF = 0,
+ KX_TRUE,
+ KX_FALSE,
+ KX_BOOL_MAX
+ };
+
+
+protected:
+ /* Some conversions to go with the bool type. */
+ /** Convert a KX_TRUE, KX_FALSE in Python to a c++ value. */
+ bool PyArgToBool(int boolArg);
+
+ /** Convert a a c++ value to KX_TRUE, KX_FALSE in Python. */
+ PyObject* BoolToPyArg(bool);
+
+
+};
+
+#endif
+
diff --git a/source/gameengine/GameLogic/SCA_IObject.cpp b/source/gameengine/GameLogic/SCA_IObject.cpp
new file mode 100644
index 00000000000..b1d210fd1c1
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_IObject.cpp
@@ -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 <iostream>
+
+#include "SCA_IObject.h"
+#include "SCA_ISensor.h"
+#include "SCA_IController.h"
+#include "SCA_IActuator.h"
+#include "MT_Point3.h"
+#include "ListValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+MT_Point3 SCA_IObject::m_sDummy=MT_Point3(0,0,0);
+
+SCA_IObject::SCA_IObject(PyTypeObject* T): CValue(T)
+{
+ m_suspended = false;
+}
+
+
+
+SCA_IObject::~SCA_IObject()
+{
+ SCA_SensorList::iterator its;
+ for (its = m_sensors.begin(); !(its == m_sensors.end()); ++its)
+ {
+ ((CValue*)(*its))->Release();
+ }
+ SCA_ControllerList::iterator itc;
+ for (itc = m_controllers.begin(); !(itc == m_controllers.end()); ++itc)
+ {
+ ((CValue*)(*itc))->Release();
+ }
+ SCA_ActuatorList::iterator ita;
+ for (ita = m_actuators.begin(); !(ita==m_actuators.end()); ++ita)
+ {
+ ((CValue*)(*ita))->Release();
+ }
+
+ //T_InterpolatorList::iterator i;
+ //for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ // delete *i;
+ //}
+}
+
+
+
+SCA_ControllerList& SCA_IObject::GetControllers()
+{
+ return m_controllers;
+}
+
+
+
+SCA_SensorList& SCA_IObject::GetSensors()
+{
+ return m_sensors;
+}
+
+
+
+SCA_ActuatorList& SCA_IObject::GetActuators()
+{
+ return m_actuators;
+}
+
+
+
+void SCA_IObject::AddSensor(SCA_ISensor* act)
+{
+ m_sensors.push_back(act);
+}
+
+
+
+void SCA_IObject::AddController(SCA_IController* act)
+{
+ m_controllers.push_back(act);
+}
+
+
+
+void SCA_IObject::AddActuator(SCA_IActuator* act)
+{
+ m_actuators.push_back(act);
+}
+
+
+
+void SCA_IObject::SetIgnoreActivityCulling(bool b)
+{
+ m_ignore_activity_culling = b;
+}
+
+
+
+bool SCA_IObject::GetIgnoreActivityCulling()
+{
+ return m_ignore_activity_culling;
+}
+
+
+
+void SCA_IObject::ReParentLogic()
+{
+ SCA_SensorList& oldsensors = GetSensors();
+
+ int sen = 0;
+ SCA_SensorList::iterator its;
+ for (its = oldsensors.begin(); !(its==oldsensors.end()); ++its)
+ {
+ SCA_ISensor* newsensor = (SCA_ISensor*)(*its)->GetReplica();
+ newsensor->ReParent(this);
+ oldsensors[sen++] = newsensor;
+ }
+
+ SCA_ControllerList& oldcontrollers = GetControllers();
+ int con = 0;
+ SCA_ControllerList::iterator itc;
+ for (itc = oldcontrollers.begin(); !(itc==oldcontrollers.end()); ++itc)
+ {
+ SCA_IController* newcontroller = (SCA_IController*)(*itc)->GetReplica();
+ newcontroller->ReParent(this);
+ oldcontrollers[con++]=newcontroller;
+
+ }
+ SCA_ActuatorList& oldactuators = GetActuators();
+
+ int act = 0;
+ SCA_ActuatorList::iterator ita;
+ for (ita = oldactuators.begin(); !(ita==oldactuators.end()); ++ita)
+ {
+ SCA_IActuator* newactuator = (SCA_IActuator*) (*ita)->GetReplica();
+ newactuator->ReParent(this);
+ newactuator->SetActive(false);
+ oldactuators[act++] = newactuator;
+ }
+
+}
+
+
+
+SCA_ISensor* SCA_IObject::FindSensor(const STR_String& sensorname)
+{
+ SCA_ISensor* foundsensor = NULL;
+
+ for (SCA_SensorList::iterator its = m_sensors.begin();!(its==m_sensors.end());its++)
+ {
+ if ((*its)->GetName() == sensorname)
+ {
+ foundsensor = (*its);
+ break;
+ }
+ }
+ return foundsensor;
+}
+
+
+
+SCA_IController* SCA_IObject::FindController(const STR_String& controllername)
+{
+ SCA_IController* foundcontroller = NULL;
+
+ for (SCA_ControllerList::iterator itc = m_controllers.begin();!(itc==m_controllers.end());itc++)
+ {
+ if ((*itc)->GetName() == controllername)
+ {
+ foundcontroller = (*itc);
+ break;
+ }
+ }
+ return foundcontroller;
+}
+
+
+
+SCA_IActuator* SCA_IObject::FindActuator(const STR_String& actuatorname)
+{
+ SCA_IActuator* foundactuator = NULL;
+
+ for (SCA_ActuatorList::iterator ita = m_actuators.begin();!(ita==m_actuators.end());ita++)
+ {
+ if ((*ita)->GetName() == actuatorname)
+ {
+ foundactuator = (*ita);
+ break;
+ }
+ }
+
+ return foundactuator;
+}
+
+
+
+void SCA_IObject::SetCurrentTime(float currentTime) {
+ //T_InterpolatorList::iterator i;
+ //for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ // (*i)->Execute(currentTime);
+ //}
+}
+
+
+#if 0
+const MT_Point3& SCA_IObject::ConvertPythonPylist(PyObject* pylist)
+{
+ bool error = false;
+ m_sDummy = MT_Vector3(0,0,0);
+ if (pylist->ob_type == &CListValue::Type)
+ {
+ CListValue* listval = (CListValue*) pylist;
+ int numelem = listval->GetCount();
+ if ( numelem <= 3)
+ {
+ int index;
+ for (index = 0;index<numelem;index++)
+ {
+ m_sDummy[index] = listval->GetValue(index)->GetNumber();
+ }
+ } else
+ {
+ error = true;
+ }
+
+ } else
+ {
+
+ // assert the list is long enough...
+ int numitems = PyList_Size(pylist);
+ if (numitems <= 3)
+ {
+ int index;
+ for (index=0;index<numitems;index++)
+ {
+ m_sDummy[index] = PyFloat_AsDouble(PyList_GetItem(pylist,index));
+ }
+ }
+ else
+ {
+ error = true;
+ }
+
+ }
+ return m_sDummy;
+}
+#endif
+
+void SCA_IObject::Suspend(void)
+{
+ if ((!m_ignore_activity_culling)
+ && (!m_suspended)) {
+ m_suspended = true;
+ /* flag suspend for all sensors */
+ SCA_SensorList::iterator i = m_sensors.begin();
+ while (i != m_sensors.end()) {
+ (*i)->Suspend();
+ i++;
+ }
+ }
+}
+
+
+
+void SCA_IObject::Resume(void)
+{
+ if (m_suspended) {
+ m_suspended = false;
+ /* unflag suspend for all sensors */
+ SCA_SensorList::iterator i = m_sensors.begin();
+ while (i != m_sensors.end()) {
+ (*i)->Resume();
+ i++;
+ }
+ }
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject SCA_IObject::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_IObject",
+ sizeof(SCA_IObject),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+
+PyParentObject SCA_IObject::Parents[] = {
+ &SCA_IObject::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+PyMethodDef SCA_IObject::Methods[] = {
+ //{"setOrientation", (PyCFunction) SCA_IObject::sPySetOrientation, METH_VARARGS},
+ //{"getOrientation", (PyCFunction) SCA_IObject::sPyGetOrientation, METH_VARARGS},
+ {NULL,NULL} //Sentinel
+};
+
+
+
+PyObject* SCA_IObject::_getattr(const STR_String& attr) {
+ _getattr_up(CValue);
+}
+
diff --git a/source/gameengine/GameLogic/SCA_IObject.h b/source/gameengine/GameLogic/SCA_IObject.h
new file mode 100644
index 00000000000..aed1d87b929
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_IObject.h
@@ -0,0 +1,129 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * An abstract object that has some logic, python scripting and
+ * reference counting Note: transformation stuff has been moved to
+ * SceneGraph
+ */
+
+#ifndef SCA_IOBJECT_H
+#define SCA_IOBJECT_H
+
+#include "Value.h"
+#include <vector>
+
+class SCA_ISensor;
+class SCA_IController;
+class SCA_IActuator;
+
+template<class T> T PyVecTo(PyObject*);
+
+typedef std::vector<SCA_ISensor *> SCA_SensorList;
+typedef std::vector<SCA_IController *> SCA_ControllerList;
+typedef std::vector<SCA_IActuator *> SCA_ActuatorList;
+
+class SCA_IObject : public CValue
+{
+
+ Py_Header;
+
+protected:
+ SCA_SensorList m_sensors;
+ SCA_ControllerList m_controllers;
+ SCA_ActuatorList m_actuators;
+ static class MT_Point3 m_sDummy;
+
+ /**
+ * Ignore activity culling requests?
+ */
+ bool m_ignore_activity_culling;
+
+ /**
+ * Ignore updates?
+ */
+ bool m_suspended;
+
+public:
+
+ SCA_IObject(PyTypeObject* T=&Type);
+ virtual ~SCA_IObject();
+
+ SCA_ControllerList& GetControllers();
+ SCA_SensorList& GetSensors();
+ SCA_ActuatorList& GetActuators();
+
+ void AddSensor(SCA_ISensor* act);
+ void AddController(SCA_IController* act);
+ void AddActuator(SCA_IActuator* act);
+
+ SCA_ISensor* FindSensor(const STR_String& sensorname);
+ SCA_IActuator* FindActuator(const STR_String& actuatorname);
+ SCA_IController* FindController(const STR_String& controllername);
+
+ void SetCurrentTime(float currentTime);
+
+ void ReParentLogic();
+
+ /**
+ * Set whether or not to ignore activity culling requests
+ */
+ void SetIgnoreActivityCulling(bool b);
+
+ /**
+ * Set whether or not this object wants to ignore activity culling
+ * requests
+ */
+ bool GetIgnoreActivityCulling();
+
+ /**
+ * Suspend all progress.
+ */
+ void Suspend(void);
+
+ /**
+ * Resume progress
+ */
+ void Resume(void);
+
+// const class MT_Point3& ConvertPythonPylist(PyObject* pylist);
+
+ // here come the python forwarded methods
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ virtual int GetGameObjectType() {return -1;}
+
+ typedef enum ObjectTypes {
+ OBJ_ARMATURE=0
+ }ObjectTypes;
+
+};
+
+#endif //SCA_IOBJECT_H
+
diff --git a/source/gameengine/GameLogic/SCA_IScene.cpp b/source/gameengine/GameLogic/SCA_IScene.cpp
new file mode 100644
index 00000000000..d4463196379
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_IScene.cpp
@@ -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 "SCA_IScene.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+SCA_IScene::SCA_IScene()
+{
+}
+
+
+
+SCA_IScene::~SCA_IScene()
+{
+ // release debugprop list
+ for (std::vector<SCA_DebugProp*>::iterator it = m_debugList.begin();
+ !(it==m_debugList.end());it++)
+ {
+ delete (*it);
+ }
+}
+
+
+std::vector<SCA_DebugProp*>& SCA_IScene::GetDebugProperties()
+{
+ return m_debugList;
+}
+
+
+
+void SCA_IScene::AddDebugProperty(class CValue* debugprop,
+ const STR_String &name)
+{
+ SCA_DebugProp* dprop = new SCA_DebugProp();
+ dprop->m_obj = debugprop;
+ dprop->m_name = name;
+ m_debugList.push_back(dprop);
+}
diff --git a/source/gameengine/GameLogic/SCA_IScene.h b/source/gameengine/GameLogic/SCA_IScene.h
new file mode 100644
index 00000000000..3c62ec91515
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_IScene.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 __KX_ISCENE_H
+#define __KX_ISCENE_H
+
+#include <vector>
+
+#include "STR_String.h"
+
+struct SCA_DebugProp
+{
+ class CValue* m_obj;
+ STR_String m_name;
+};
+
+class SCA_IScene
+{
+ std::vector<SCA_DebugProp*> m_debugList;
+public:
+ SCA_IScene();
+ virtual ~SCA_IScene();
+ virtual class SCA_IObject* AddReplicaObject(class CValue* gameobj,
+ class CValue* locationobj,
+ int lifespan=0)=0;
+ virtual void RemoveObject(class CValue* gameobj)=0;
+ virtual void DelayedRemoveObject(class CValue* gameobj)=0;
+ virtual void DelayedReleaseObject(class CValue* gameobj)=0;
+
+ virtual void ReplaceMesh(class CValue* gameobj,
+ void* meshobj)=0;
+ std::vector<SCA_DebugProp*>& GetDebugProperties();
+ void AddDebugProperty(class CValue* debugprop,
+ const STR_String &name);
+};
+
+#endif //__KX_ISCENE_H
+
diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp
new file mode 100644
index 00000000000..43dd6bef83e
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ISensor.cpp
@@ -0,0 +1,334 @@
+/**
+ * Abstract class for sensor logic bricks
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_ISensor.h"
+#include "SCA_EventManager.h"
+#include "SCA_LogicManager.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* Native functions */
+void SCA_ISensor::ReParent(SCA_IObject* parent)
+{
+ SCA_ILogicBrick::ReParent(parent);
+ m_eventmgr->RegisterSensor(this);
+ this->SetActive(false);
+}
+
+
+SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj,
+ class SCA_EventManager* eventmgr,
+ PyTypeObject* T ) :
+ SCA_ILogicBrick(gameobj,T),
+ m_triggered(false)
+{
+ m_suspended = false;
+ m_invert = false;
+ m_pos_ticks = 0;
+ m_neg_ticks = 0;
+ m_pos_pulsemode = false;
+ m_neg_pulsemode = false;
+ m_pulse_frequency = 0;
+
+ m_eventmgr = eventmgr;
+}
+
+
+SCA_ISensor::~SCA_ISensor()
+{
+ // intentionally empty
+}
+
+bool SCA_ISensor::IsPositiveTrigger() {
+ bool result = false;
+
+ if (m_eventval) {
+ result = (m_eventval->GetNumber() != 0.0);
+ }
+ if (m_invert) {
+ result = !result;
+ }
+
+ return result;
+}
+
+void SCA_ISensor::SetPulseMode(bool posmode,
+ bool negmode,
+ int freq) {
+ m_pos_pulsemode = posmode;
+ m_neg_pulsemode = negmode;
+ m_pulse_frequency = freq;
+}
+
+void SCA_ISensor::SetInvert(bool inv) {
+ m_invert = inv;
+}
+
+
+float SCA_ISensor::GetNumber() {
+ return IsPositiveTrigger();
+}
+
+void SCA_ISensor::Suspend() {
+ m_suspended = true;
+}
+
+bool SCA_ISensor::IsSuspended() {
+ return m_suspended;
+}
+
+void SCA_ISensor::Resume() {
+ m_suspended = false;
+}
+
+/* python integration */
+
+PyTypeObject SCA_ISensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_ISensor",
+ sizeof(SCA_ISensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_ISensor::Parents[] = {
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+PyMethodDef SCA_ISensor::Methods[] = {
+ {"isPositive", (PyCFunction) SCA_ISensor::sPyIsPositive,
+ METH_VARARGS, IsPositive_doc},
+ {"getUsePosPulseMode", (PyCFunction) SCA_ISensor::sPyGetUsePosPulseMode,
+ METH_VARARGS, GetUsePosPulseMode_doc},
+ {"setUsePosPulseMode", (PyCFunction) SCA_ISensor::sPySetUsePosPulseMode,
+ METH_VARARGS, SetUsePosPulseMode_doc},
+ {"getFrequency", (PyCFunction) SCA_ISensor::sPyGetFrequency,
+ METH_VARARGS, GetFrequency_doc},
+ {"setFrequency", (PyCFunction) SCA_ISensor::sPySetFrequency,
+ METH_VARARGS, SetFrequency_doc},
+ {"getUseNegPulseMode", (PyCFunction) SCA_ISensor::sPyGetUseNegPulseMode,
+ METH_VARARGS, GetUseNegPulseMode_doc},
+ {"setUseNegPulseMode", (PyCFunction) SCA_ISensor::sPySetUseNegPulseMode,
+ METH_VARARGS, SetUseNegPulseMode_doc},
+ {"getInvert", (PyCFunction) SCA_ISensor::sPyGetInvert,
+ METH_VARARGS, GetInvert_doc},
+ {"setInvert", (PyCFunction) SCA_ISensor::sPySetInvert,
+ METH_VARARGS, SetInvert_doc},
+ {NULL,NULL} //Sentinel
+};
+
+
+PyObject*
+SCA_ISensor::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_ILogicBrick);
+}
+
+
+void SCA_ISensor::RegisterToManager()
+{
+ m_eventmgr->RegisterSensor(this);
+}
+
+void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr, CValue* event)
+{
+
+ // calculate if a __triggering__ is wanted
+ if (!m_suspended) {
+ bool result = this->Evaluate(event);
+ if (result) {
+ logicmgr->AddActivatedSensor(this);
+ } else
+ {
+ /* First, the pulsing behaviour, if pulse mode is
+ * active. It seems something goes wrong if pulse mode is
+ * not set :( */
+ if (m_pos_pulsemode) {
+ m_pos_ticks++;
+ if (m_pos_ticks > m_pulse_frequency) {
+ if ( this->IsPositiveTrigger() )
+ {
+ logicmgr->AddActivatedSensor(this);
+ }
+ m_pos_ticks = 0;
+ }
+ }
+
+ if (m_neg_pulsemode)
+ {
+ m_neg_ticks++;
+ if (m_neg_ticks > m_pulse_frequency) {
+ if (!this->IsPositiveTrigger() )
+ {
+ logicmgr->AddActivatedSensor(this);
+ }
+ m_neg_ticks = 0;
+ }
+ }
+ }
+ }
+}
+
+/* Python functions: */
+char SCA_ISensor::IsPositive_doc[] =
+"isPositive()\n"
+"\tReturns whether the sensor is registered a positive event.\n";
+PyObject* SCA_ISensor::PyIsPositive(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int retval = IsPositiveTrigger();
+ return PyInt_FromLong(retval);
+}
+
+/**
+ * getUsePulseMode: getter for the pulse mode (KX_TRUE = on)
+ */
+char SCA_ISensor::GetUsePosPulseMode_doc[] =
+"getUsePosPulseMode()\n"
+"\tReturns whether positive pulse mode is active.\n";
+PyObject* SCA_ISensor::PyGetUsePosPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return BoolToPyArg(m_pos_pulsemode);
+}
+
+/**
+ * setUsePulseMode: setter for the pulse mode (KX_TRUE = on)
+ */
+char SCA_ISensor::SetUsePosPulseMode_doc[] =
+"setUsePosPulseMode(pulse?)\n"
+"\t - pulse? : Pulse when a positive event occurs?\n"
+"\t (KX_TRUE, KX_FALSE)\n"
+"\tSet whether to do pulsing when positive pulses occur.\n";
+PyObject* SCA_ISensor::PySetUsePosPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int pyarg = 0;
+ if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
+ m_pos_pulsemode = PyArgToBool(pyarg);
+ Py_Return;
+}
+
+/**
+ * getFrequency: getter for the pulse mode interval
+ */
+char SCA_ISensor::GetFrequency_doc[] =
+"getFrequency()\n"
+"\tReturns the frequency of the updates in pulse mode.\n" ;
+PyObject* SCA_ISensor::PyGetFrequency(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyInt_FromLong(m_pulse_frequency);
+}
+
+/**
+ * setFrequency: setter for the pulse mode (KX_TRUE = on)
+ */
+char SCA_ISensor::SetFrequency_doc[] =
+"setFrequency(pulse_frequency)\n"
+"\t- pulse_frequency: The frequency of the updates in pulse mode (integer)"
+"\tSet the frequency of the updates in pulse mode.\n"
+"\tIf the frequency is negative, it is set to 0.\n" ;
+PyObject* SCA_ISensor::PySetFrequency(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int pulse_frequencyArg = 0;
+
+ if(!PyArg_ParseTuple(args, "i", &pulse_frequencyArg)) {
+ return NULL;
+ }
+
+ /* We can do three things here: clip, ignore and raise an exception. */
+ /* Exceptions don't work yet, ignoring is not desirable now... */
+ if (pulse_frequencyArg < 0) {
+ pulse_frequencyArg = 0;
+ };
+ m_pulse_frequency = pulse_frequencyArg;
+
+ Py_Return;
+}
+
+
+char SCA_ISensor::GetInvert_doc[] =
+"getInvert()\n"
+"\tReturns whether or not pulses from this sensor are inverted.\n" ;
+PyObject* SCA_ISensor::PyGetInvert(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return BoolToPyArg(m_invert);
+}
+
+char SCA_ISensor::SetInvert_doc[] =
+"setInvert(invert?)\n"
+"\t- invert?: Invert the event-values? (KX_TRUE, KX_FALSE)\n"
+"\tSet whether to invert pulses.\n";
+PyObject* SCA_ISensor::PySetInvert(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int pyarg = 0;
+ if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
+ m_invert = PyArgToBool(pyarg);
+ Py_Return;
+}
+
+char SCA_ISensor::GetUseNegPulseMode_doc[] =
+"getUseNegPulseMode()\n"
+"\tReturns whether negative pulse mode is active.\n";
+PyObject* SCA_ISensor::PyGetUseNegPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return BoolToPyArg(m_neg_pulsemode);
+}
+
+char SCA_ISensor::SetUseNegPulseMode_doc[] =
+"setUseNegPulseMode(pulse?)\n"
+"\t - pulse? : Pulse when a negative event occurs?\n"
+"\t (KX_TRUE, KX_FALSE)\n"
+"\tSet whether to do pulsing when negative pulses occur.\n";
+PyObject* SCA_ISensor::PySetUseNegPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int pyarg = 0;
+ if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
+ m_neg_pulsemode = PyArgToBool(pyarg);
+ Py_Return;
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h
new file mode 100644
index 00000000000..fb2dca97d06
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ISensor.h
@@ -0,0 +1,129 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Interface Class for all logic Sensors. Implements
+ * pulsemode and pulsefrequency, and event suppression.
+ */
+
+#ifndef __SCA_ISENSOR
+#define __SCA_ISENSOR
+
+#include "SCA_ILogicBrick.h"
+
+/**
+ * Interface Class for all logic Sensors. Implements
+ * pulsemode,pulsefrequency */
+class SCA_ISensor : public SCA_ILogicBrick
+{
+ Py_Header;
+ class SCA_EventManager* m_eventmgr;
+ bool m_triggered;
+
+ /** Pulse positive pulses? */
+ bool m_pos_pulsemode;
+
+ /** Pulse negative pulses? */
+ bool m_neg_pulsemode;
+
+ /** Repeat frequency in pulse mode. */
+ int m_pulse_frequency;
+
+ /** Number of ticks since the last positive pulse. */
+ int m_pos_ticks;
+
+ /** Number of ticks since the last negative pulse. */
+ int m_neg_ticks;
+
+ /** invert the output signal*/
+ bool m_invert;
+
+ /** Sensor must ignore updates? */
+ bool m_suspended;
+
+ /** Pass the activation on to the logic manager.*/
+ void SignalActivation(class SCA_LogicManager* logicmgr);
+
+public:
+ SCA_ISensor(SCA_IObject* gameobj,
+ class SCA_EventManager* eventmgr,
+ PyTypeObject* T );;
+ ~SCA_ISensor();
+ virtual void ReParent(SCA_IObject* parent);
+
+ /** Because we want sensors to share some behaviour, the Activate has */
+ /* an implementation on this level. It requires an evaluate on the lower */
+ /* level of individual sensors. Mapping the old activate()s is easy. */
+ /* The IsPosTrig() also has to change, to keep things consistent. */
+ void Activate(class SCA_LogicManager* logicmgr,CValue* event);
+ virtual bool Evaluate(CValue* event) = 0;
+ virtual bool IsPositiveTrigger();
+
+ virtual PyObject* _getattr(const STR_String& attr);
+ virtual CValue* GetReplica()=0;
+
+ /** Set parameters for the pulsing behaviour.
+ * @param posmode Trigger positive pulses?
+ * @param negmode Trigger negative pulses?
+ * @param freq Frequency to use when doing pulsing.
+ */
+ void SetPulseMode(bool posmode,
+ bool negmode,
+ int freq);
+
+ /** Set inversion of pulses on or off. */
+ void SetInvert(bool inv);
+
+ void RegisterToManager();
+ virtual float GetNumber();
+
+ /** Stop sensing for a while. */
+ void Suspend();
+
+ /** Is this sensor switched off? */
+ bool IsSuspended();
+
+ /** Resume sensing. */
+ void Resume();
+
+ /* Python functions: */
+ KX_PYMETHOD_DOC(SCA_ISensor,IsPositive);
+ KX_PYMETHOD_DOC(SCA_ISensor,GetUsePosPulseMode);
+ KX_PYMETHOD_DOC(SCA_ISensor,SetUsePosPulseMode);
+ KX_PYMETHOD_DOC(SCA_ISensor,GetFrequency);
+ KX_PYMETHOD_DOC(SCA_ISensor,SetFrequency);
+ KX_PYMETHOD_DOC(SCA_ISensor,GetUseNegPulseMode);
+ KX_PYMETHOD_DOC(SCA_ISensor,SetUseNegPulseMode);
+ KX_PYMETHOD_DOC(SCA_ISensor,GetInvert);
+ KX_PYMETHOD_DOC(SCA_ISensor,SetInvert);
+
+};
+
+#endif //__SCA_ISENSOR
+
diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.cpp b/source/gameengine/GameLogic/SCA_JoystickManager.cpp
new file mode 100644
index 00000000000..cf182a0503e
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_JoystickManager.cpp
@@ -0,0 +1,84 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_JoystickSensor.h"
+#include "SCA_JoystickManager.h"
+#include "SCA_LogicManager.h"
+//#include <vector>
+#include "SCA_ISensor.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+//using namespace std;
+
+
+SCA_JoystickManager::SCA_JoystickManager(class SCA_LogicManager* logicmgr)
+ : SCA_EventManager(JOY_EVENTMGR),
+ m_logicmgr(logicmgr)
+{
+ m_joystick = new SCA_Joystick();
+ m_joystick->CreateJoystickDevice();
+}
+
+
+SCA_JoystickManager::~SCA_JoystickManager()
+{
+ m_joystick->DestroyJoystickDevice();
+ delete m_joystick;
+}
+
+
+void SCA_JoystickManager::NextFrame(double curtime,double deltatime)
+{
+ for (unsigned int i = 0; i < m_sensors.size(); i++)
+ {
+ SCA_JoystickSensor* joysensor = (SCA_JoystickSensor*) m_sensors[i];
+ if(!joysensor->IsSuspended())
+ {
+ m_joystick->HandleEvents();
+ joysensor->Activate(m_logicmgr, NULL);
+ }
+ }
+}
+
+
+void SCA_JoystickManager::RegisterSensor(SCA_ISensor* sensor)
+{
+ m_sensors.push_back(sensor);
+}
+
+
+SCA_Joystick *SCA_JoystickManager::GetJoystickDevice()
+{
+ /*
+ *Return the instance of SCA_Joystick for use
+ */
+ return m_joystick;
+}
diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.h b/source/gameengine/GameLogic/SCA_JoystickManager.h
new file mode 100644
index 00000000000..5c892d71f6c
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_JoystickManager.h
@@ -0,0 +1,57 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __JOYSTICKMANAGER_H_
+#define __JOYSTICKMANAGER_H_
+
+#include "SCA_EventManager.h"
+#include "Joystick/SCA_Joystick.h"
+#include <vector>
+
+using namespace std;
+class SCA_JoystickManager : public SCA_EventManager
+{
+
+ class SCA_LogicManager* m_logicmgr;
+ /**
+ * SDL Joystick Class Instance
+ */
+ SCA_Joystick *m_joystick;
+public:
+ SCA_JoystickManager(class SCA_LogicManager* logicmgr);
+ virtual ~SCA_JoystickManager();
+ virtual void NextFrame(double curtime,double deltatime);
+ virtual void RegisterSensor(SCA_ISensor* sensor);
+ SCA_Joystick* GetJoystickDevice(void);
+
+};
+
+#endif
+
diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
new file mode 100644
index 00000000000..40942dd296f
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
@@ -0,0 +1,476 @@
+/*
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_JoystickManager.h"
+#include "SCA_JoystickSensor.h"
+
+#include "SCA_EventManager.h"
+#include "SCA_LogicManager.h"
+
+#include <iostream>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+SCA_JoystickSensor::SCA_JoystickSensor(class SCA_JoystickManager* eventmgr,
+ SCA_IObject* gameobj,
+ short int joymode,
+ int axis, int axisf,int prec,
+ int button, int buttonf,
+ int hat, int hatf,
+ PyTypeObject* T )
+ :SCA_ISensor(gameobj,eventmgr,T),
+ m_pJoystickMgr(eventmgr),
+ m_axis(axis),
+ m_axisf(axisf),
+ m_button(button),
+ m_buttonf(buttonf),
+ m_hat(hat),
+ m_hatf(hatf),
+ m_precision(prec),
+ m_joymode(joymode)
+{
+/*
+std::cout << " axis " << m_axis << std::endl;
+std::cout << " axis flag " << m_axisf << std::endl;
+std::cout << " precision " << m_precision << std::endl;
+std::cout << " button " << m_button << std::endl;
+std::cout << " button flag "<< m_buttonf << std::endl;
+std::cout << " hat " << m_hat << std::endl;
+std::cout << " hat flag " << m_hatf << std::endl;
+*/
+ m_istrig=0;
+}
+
+
+SCA_JoystickSensor::~SCA_JoystickSensor()
+{
+}
+
+
+CValue* SCA_JoystickSensor::GetReplica()
+{
+ CValue* replica = new SCA_JoystickSensor(*this);
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+}
+
+
+bool SCA_JoystickSensor::IsPositiveTrigger()
+{
+ bool result = m_istrig;
+ if (m_invert)
+ result = !result;
+ return result;
+}
+
+
+bool SCA_JoystickSensor::Evaluate(CValue* event)
+{
+ SCA_Joystick *js = m_pJoystickMgr->GetJoystickDevice();
+ bool result = false;
+
+ switch(m_joymode)
+ {
+ case KX_JOYSENSORMODE_AXIS:
+ {
+ /* what is what!
+ m_axisf == 0 == right
+ m_axisf == 1 == up
+ m_axisf == 2 == left
+ m_axisf == 3 == down
+ numberof== m_axis -- max 2
+ */
+ js->cSetPrecision(m_precision);
+ if(m_axisf == 1){
+ if(js->aUpAxisIsPositive(m_axis)){
+ m_istrig =1;
+ result = true;
+ }else{
+ if(m_istrig){
+ m_istrig = 0;
+ result = true;
+ }
+ }
+ }
+ if(m_axisf == 3){
+ if(js->aDownAxisIsPositive(m_axis)){
+ m_istrig = 1;
+ result = true;
+ }else{
+ if(m_istrig){
+ m_istrig = 0;
+ result = true;
+ }
+ }
+ }
+ if(m_axisf == 2){
+ if(js->aLeftAxisIsPositive(m_axis)){
+ m_istrig = 1;
+ result = true;
+ }else{
+ if(m_istrig){
+ m_istrig = 0;
+ result = true;
+ }
+ }
+ }
+ if(m_axisf == 0){
+ if(js->aRightAxisIsPositive(m_axis)){
+ m_istrig = 1;
+ result = true;
+ }else{
+ if(m_istrig){
+ m_istrig = 0;
+ result = true;
+ }
+ }
+ }
+ break;
+ }
+ case KX_JOYSENSORMODE_BUTTON:
+ {
+ /* what is what!
+ pressed = m_buttonf == 0
+ released = m_buttonf == 1
+ m_button = the actual button in question
+ */
+ if(m_buttonf == 0){
+ if(js->aButtonPressIsPositive(m_button)){
+ m_istrig = 1;
+ result = true;
+ }else {
+ if(m_istrig){
+ m_istrig = 0;
+ result = true;
+ }
+ }
+ }
+ if(m_buttonf == 1){
+ if(js->aButtonReleaseIsPositive(m_button)){
+ m_istrig = 1;
+ result = true;
+ }else {
+ if(m_istrig){
+ m_istrig = 0;
+ result = true;
+ }
+ }
+ }
+ break;
+ }
+ case KX_JOYSENSORMODE_HAT:
+ {
+ /* what is what!
+ numberof = m_hat -- max 2
+ direction= m_hatf -- max 12
+ */
+ if(m_hat == 1){
+ if(js->aHatIsPositive(m_hatf)){
+ m_istrig = 1;
+ result = true;
+ }else{
+ if(m_istrig){
+ m_istrig = 0;
+ result = true;
+ }
+ }
+ }
+ if(m_hat == 2){
+ if(js->aHatIsPositive(m_hatf)){
+ m_istrig = 1;
+ result = true;
+ }else{
+ if(m_istrig){
+ m_istrig = 0;
+ result = true;
+ }
+ }
+ }
+ /*
+ if(m_hat == 3){
+ if(js->aHatIsPositive(m_hatf)){
+ m_istrig = 1;
+ result = true;
+ }else{
+ if(m_istrig){
+ m_istrig = 0;
+ result = true;
+ }
+ }
+ }
+ */
+ break;
+ }
+ /* test for ball anyone ?*/
+ default:
+ printf("Error invalid switch statement\n");
+ break;
+ }
+ if(!js->IsTrig()){
+ m_istrig = 0;
+ }
+ return result;
+}
+
+
+bool SCA_JoystickSensor::isValid(SCA_JoystickSensor::KX_JOYSENSORMODE m)
+{
+ bool res = false;
+ res = ((m > KX_JOYSENSORMODE_NODEF) && (m < KX_JOYSENSORMODE_MAX));
+ return res;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject SCA_JoystickSensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_JoystickSensor",
+ sizeof(SCA_JoystickSensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+PyParentObject SCA_JoystickSensor::Parents[] = {
+ &SCA_JoystickSensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+PyMethodDef SCA_JoystickSensor::Methods[] = {
+ {"getAxis", (PyCFunction) SCA_JoystickSensor::sPyGetAxis, METH_NOARGS, GetAxis_doc},
+ {"setAxis", (PyCFunction) SCA_JoystickSensor::sPySetAxis, METH_VARARGS, SetAxis_doc},
+ {"getAxisValue", (PyCFunction) SCA_JoystickSensor::sPyGetRealAxis, METH_NOARGS, GetRealAxis_doc},
+ {"getThreshold", (PyCFunction) SCA_JoystickSensor::sPyGetThreshold, METH_NOARGS, GetThreshold_doc},
+ {"setThreshold", (PyCFunction) SCA_JoystickSensor::sPySetThreshold, METH_VARARGS, SetThreshold_doc},
+ {"getButton", (PyCFunction) SCA_JoystickSensor::sPyGetButton, METH_NOARGS, GetButton_doc},
+ {"setButton", (PyCFunction) SCA_JoystickSensor::sPySetButton, METH_VARARGS, SetButton_doc},
+ {"getHat", (PyCFunction) SCA_JoystickSensor::sPyGetHat, METH_NOARGS, GetHat_doc},
+ {"setHat", (PyCFunction) SCA_JoystickSensor::sPySetHat, METH_VARARGS, SetHat_doc},
+ {"getNumAxes", (PyCFunction) SCA_JoystickSensor::sPyNumberOfAxes, METH_NOARGS, NumberOfAxes_doc},
+ {"getNumButtons",(PyCFunction) SCA_JoystickSensor::sPyNumberOfButtons,METH_NOARGS, NumberOfButtons_doc},
+ {"getNumHats", (PyCFunction) SCA_JoystickSensor::sPyNumberOfHats, METH_NOARGS, NumberOfHats_doc},
+ {NULL,NULL} //Sentinel
+};
+
+
+PyObject* SCA_JoystickSensor::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_ISensor);
+}
+
+
+/* get axis ---------------------------------------------------------- */
+char SCA_JoystickSensor::GetAxis_doc[] =
+"getAxis\n"
+"\tReturns the current state of the axis.\n";
+PyObject* SCA_JoystickSensor::PyGetAxis( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return Py_BuildValue("[ii]",m_axis, m_axisf);
+}
+
+
+/* set axis ---------------------------------------------------------- */
+char SCA_JoystickSensor::SetAxis_doc[] =
+"setAxis\n"
+"\tSets the current state of the axis.\n";
+PyObject* SCA_JoystickSensor::PySetAxis( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+
+ int axis,axisflag;
+ if(!PyArg_ParseTuple(args, "ii", &axis, &axisflag)){
+ return NULL;
+ }
+ m_axis = axis;
+ m_axisf = axisflag;
+ Py_Return;
+}
+
+
+/* get axis value ----------------------------------------------------- */
+char SCA_JoystickSensor::GetRealAxis_doc[] =
+"getAxisValue\n"
+"\tReturns a list of the values for each axis .\n";
+PyObject* SCA_JoystickSensor::PyGetRealAxis( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int a,b,c,d;
+ SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice();
+ a = joy->GetAxis10();
+ b = joy->GetAxis11();
+ c = joy->GetAxis20();
+ d = joy->GetAxis21();
+ return Py_BuildValue("[iiii]",a,b,c,d);
+}
+
+
+/* get threshold ----------------------------------------------------- */
+char SCA_JoystickSensor::GetThreshold_doc[] =
+"getThreshold\n"
+"\tReturns the threshold of the axis.\n";
+PyObject* SCA_JoystickSensor::PyGetThreshold( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return Py_BuildValue("i", m_precision);
+}
+
+
+/* set threshold ----------------------------------------------------- */
+char SCA_JoystickSensor::SetThreshold_doc[] =
+"setThreshold\n"
+"\tSets the threshold of the axis.\n";
+PyObject* SCA_JoystickSensor::PySetThreshold( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int thresh;
+ if(!PyArg_ParseTuple(args, "i", &thresh)){
+ return NULL;
+ }
+ m_precision = thresh;
+ Py_Return;
+}
+
+
+/* get button -------------------------------------------------------- */
+char SCA_JoystickSensor::GetButton_doc[] =
+"getButton\n"
+"\tReturns the currently pressed button.\n";
+PyObject* SCA_JoystickSensor::PyGetButton( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return Py_BuildValue("[ii]",m_button, m_buttonf);
+}
+
+
+/* set button -------------------------------------------------------- */
+char SCA_JoystickSensor::SetButton_doc[] =
+"setButton\n"
+"\tSets the button the sensor reacts to.\n";
+PyObject* SCA_JoystickSensor::PySetButton( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int button,buttonflag;
+ if(!PyArg_ParseTuple(args, "ii", &button, &buttonflag)){
+ return NULL;
+ }
+ m_button = button;
+ m_buttonf = buttonflag;
+ Py_Return;
+}
+
+
+/* get hat ----------------------------------------------------------- */
+char SCA_JoystickSensor::GetHat_doc[] =
+"getHat\n"
+"\tReturns the current direction of the hat.\n";
+PyObject* SCA_JoystickSensor::PyGetHat( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return Py_BuildValue("[ii]",m_hat, m_hatf);
+}
+
+
+/* set hat ----------------------------------------------------------- */
+char SCA_JoystickSensor::SetHat_doc[] =
+"setHat\n"
+"\tSets the hat the sensor reacts to.\n";
+PyObject* SCA_JoystickSensor::PySetHat( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int hat,hatflag;
+ if(!PyArg_ParseTuple(args, "ii", &hat, &hatflag)){
+ return NULL;
+ }
+ m_hat = hat;
+ m_hatf = hatflag;
+ Py_Return;
+}
+
+
+/* get # of ----------------------------------------------------- */
+char SCA_JoystickSensor::NumberOfAxes_doc[] =
+"getNumAxes\n"
+"\tReturns the number of axes .\n";
+PyObject* SCA_JoystickSensor::PyNumberOfAxes( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int num;
+ SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice();
+ num = joy->GetNumberOfAxes();
+ return Py_BuildValue("i",num);
+}
+
+
+char SCA_JoystickSensor::NumberOfButtons_doc[] =
+"getNumButtons\n"
+"\tReturns the number of buttons .\n";
+PyObject* SCA_JoystickSensor::PyNumberOfButtons( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int num;
+ SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice();
+ num = joy->GetNumberOfButtons();
+ return Py_BuildValue("i",num);
+}
+
+
+char SCA_JoystickSensor::NumberOfHats_doc[] =
+"getNumHats\n"
+"\tReturns the number of hats .\n";
+PyObject* SCA_JoystickSensor::PyNumberOfHats( PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int num;
+ SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice();
+ num = joy->GetNumberOfHats();
+ return Py_BuildValue("i",num);
+}
diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.h b/source/gameengine/GameLogic/SCA_JoystickSensor.h
new file mode 100644
index 00000000000..08af4b84b42
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_JoystickSensor.h
@@ -0,0 +1,127 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __JOYSENSOR_H_
+#define __JOYSENSOR_H
+
+#include "SCA_ISensor.h"
+
+class SCA_JoystickSensor :public SCA_ISensor
+{
+ Py_Header;
+ class SCA_JoystickManager* m_pJoystickMgr;
+
+ /**
+ * Axis 1-or-2
+ */
+ int m_axis;
+ /**
+ * Axis flag to find direction
+ */
+ int m_axisf;
+ /**
+ * The actual button
+ */
+ int m_button;
+ /**
+ * Flag for a pressed or released button
+ */
+ int m_buttonf;
+ /**
+ * The actual hat
+ */
+ int m_hat;
+ /**
+ * Flag to find direction 1-12
+ */
+ int m_hatf;
+ /**
+ * The threshold value the axis acts opon
+ */
+ int m_precision;
+ /**
+ * Is an event triggered ?
+ */
+ bool m_istrig;
+ /**
+ * The mode to determine axis,button or hat
+ */
+ short int m_joymode;
+
+ enum KX_JOYSENSORMODE {
+ KX_JOYSENSORMODE_NODEF = 0,
+ KX_JOYSENSORMODE_AXIS,
+ KX_JOYSENSORMODE_BUTTON,
+ KX_JOYSENSORMODE_HAT,
+ KX_JOYSENSORMODE_MAX
+ };
+ bool isValid(KX_JOYSENSORMODE);
+
+public:
+ SCA_JoystickSensor(class SCA_JoystickManager* eventmgr,
+ SCA_IObject* gameobj,
+ short int joymode,
+ int axis, int axisf,int prec,
+ int button, int buttonf,
+ int hat, int hatf,
+ PyTypeObject* T=&Type );
+ virtual ~SCA_JoystickSensor();
+ virtual CValue* GetReplica();
+
+ virtual bool Evaluate(CValue* event);
+ virtual bool IsPositiveTrigger();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ /* Axes*/
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,GetAxis);
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,SetAxis);
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,GetRealAxis);
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,GetThreshold);
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,SetThreshold);
+ /* Buttons */
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,GetButton);
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,SetButton);
+ /* Hats */
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,GetHat);
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,SetHat);
+ /* number of */
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,NumberOfAxes);
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,NumberOfButtons);
+ KX_PYMETHOD_DOC(SCA_JoystickSensor,NumberOfHats);
+
+};
+
+#endif
diff --git a/source/gameengine/GameLogic/SCA_KeyboardManager.cpp b/source/gameengine/GameLogic/SCA_KeyboardManager.cpp
new file mode 100644
index 00000000000..25a366352cc
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_KeyboardManager.cpp
@@ -0,0 +1,90 @@
+/**
+ * Manager for keyboard events
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "BoolValue.h"
+#include "SCA_KeyboardManager.h"
+#include "SCA_KeyboardSensor.h"
+#include "IntValue.h"
+#include <vector>
+
+SCA_KeyboardManager::SCA_KeyboardManager(SCA_LogicManager* logicmgr,
+ SCA_IInputDevice* inputdev)
+ : SCA_EventManager(KEYBOARD_EVENTMGR),
+ m_inputDevice(inputdev),
+ m_logicmanager(logicmgr)
+{
+}
+
+
+
+SCA_KeyboardManager::~SCA_KeyboardManager()
+{
+}
+
+
+
+SCA_IInputDevice* SCA_KeyboardManager::GetInputDevice()
+{
+ return m_inputDevice;
+}
+
+
+
+void SCA_KeyboardManager::NextFrame()
+{
+ //const SCA_InputEvent& event = GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode)=0;
+ // cerr << "SCA_KeyboardManager::NextFrame"<< endl;
+ for (unsigned int i=0;i<m_sensors.size();i++)
+ {
+ SCA_KeyboardSensor* keysensor = (SCA_KeyboardSensor*)m_sensors[i];
+ keysensor->Activate(m_logicmanager,NULL);
+ }
+
+}
+
+
+
+void SCA_KeyboardManager::RegisterSensor(SCA_ISensor* keysensor)
+{
+ m_sensors.push_back(keysensor);
+}
+
+
+
+bool SCA_KeyboardManager::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode)
+{
+ return false;
+ //return m_kxsystem->IsPressed(inputcode);
+}
+
diff --git a/source/gameengine/GameLogic/SCA_KeyboardManager.h b/source/gameengine/GameLogic/SCA_KeyboardManager.h
new file mode 100644
index 00000000000..562f28417ad
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_KeyboardManager.h
@@ -0,0 +1,66 @@
+/**
+ * Manager for keyboard events
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_KEYBOARDMANAGER
+#define __KX_KEYBOARDMANAGER
+
+
+#include "SCA_EventManager.h"
+
+#include <vector>
+
+using namespace std;
+
+#include "SCA_IInputDevice.h"
+
+
+class SCA_KeyboardManager : public SCA_EventManager
+{
+ class SCA_IInputDevice* m_inputDevice;
+ class SCA_LogicManager* m_logicmanager;
+
+
+public:
+ SCA_KeyboardManager(class SCA_LogicManager* logicmgr,class SCA_IInputDevice* inputdev);
+ virtual ~SCA_KeyboardManager();
+
+ bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode);
+
+ virtual void NextFrame();
+ virtual void RegisterSensor(class SCA_ISensor* sensor);
+ SCA_IInputDevice* GetInputDevice();
+};
+
+#endif //__KX_KEYBOARDMANAGER
+
diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
new file mode 100644
index 00000000000..fb8c340b09e
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
@@ -0,0 +1,678 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Sensor for keyboard input
+ */
+#include "SCA_KeyboardSensor.h"
+#include "SCA_KeyboardManager.h"
+#include "SCA_LogicManager.h"
+#include "StringValue.h"
+#include "SCA_IInputDevice.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+SCA_KeyboardSensor::SCA_KeyboardSensor(SCA_KeyboardManager* keybdmgr,
+ short int hotkey,
+ short int qual,
+ short int qual2,
+ bool bAllKeys,
+ const STR_String& targetProp,
+ const STR_String& toggleProp,
+ SCA_IObject* gameobj,
+ PyTypeObject* T )
+ :SCA_ISensor(gameobj,keybdmgr,T),
+ m_pKeyboardMgr(keybdmgr),
+ m_hotkey(hotkey),
+ m_qual(qual),
+ m_qual2(qual2),
+ m_bAllKeys(bAllKeys),
+ m_targetprop(targetProp),
+ m_toggleprop(toggleProp)
+{
+ if (hotkey == SCA_IInputDevice::KX_ESCKEY)
+ keybdmgr->GetInputDevice()->HookEscape();
+// SetDrawColor(0xff0000ff);
+ m_val=0;
+}
+
+
+
+SCA_KeyboardSensor::~SCA_KeyboardSensor()
+{
+}
+
+
+
+CValue* SCA_KeyboardSensor::GetReplica()
+{
+ CValue* replica = new SCA_KeyboardSensor(*this);
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+short int SCA_KeyboardSensor::GetHotkey()
+{
+ return m_hotkey;
+}
+
+
+
+bool SCA_KeyboardSensor::IsPositiveTrigger()
+{
+ bool result = (m_val != 0);
+
+ if (m_invert)
+ result = !result;
+
+ return result;
+}
+
+
+
+bool SCA_KeyboardSensor::TriggerOnAllKeys()
+{
+ return m_bAllKeys;
+}
+
+
+
+bool SCA_KeyboardSensor::Evaluate(CValue* eventval)
+{
+ bool result = false;
+ SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
+
+ // cerr << "SCA_KeyboardSensor::Eval event, sensing for "<< m_hotkey << " at device " << inputdev << "\n";
+
+ /* See if we need to do logging: togPropState exists and is
+ * different from 0 */
+ CValue* myparent = GetParent();
+ CValue* togPropState = myparent->GetProperty(m_toggleprop);
+ if (togPropState &&
+ (((int)togPropState->GetNumber()) != 0) )
+ {
+ LogKeystrokes();
+ }
+
+
+
+ /* Now see whether events must be bounced. */
+ if (m_bAllKeys)
+ {
+ bool justactivated = false;
+ bool justreleased = false;
+
+ for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++)
+ {
+ const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
+ if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED)
+ {
+ justactivated = true;
+ }
+ if (inevent.m_status == SCA_InputEvent::KX_JUSTRELEASED)
+ {
+ justreleased = true;
+ }
+ }
+
+ if (justactivated)
+ {
+ m_val=1;
+ result = true;
+ } else
+ {
+ if (justreleased)
+ {
+ m_val=0;
+ result = true;
+ }
+ }
+
+
+ } else
+ {
+
+ // cerr << "======= SCA_KeyboardSensor::Evaluate:: peeking at key status" << endl;
+ const SCA_InputEvent & inevent = inputdev->GetEventValue(
+ (SCA_IInputDevice::KX_EnumInputs) m_hotkey);
+
+ // cerr << "======= SCA_KeyboardSensor::Evaluate:: status: " << inevent.m_status << endl;
+
+ if (inevent.m_status == SCA_InputEvent::KX_NO_INPUTSTATUS)
+ {
+ } else
+ {
+ if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED)
+ {
+ m_val=1;
+ result = true;
+ } else
+ {
+ if (inevent.m_status == SCA_InputEvent::KX_JUSTRELEASED)
+ {
+ m_val = 0;
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+
+}
+
+void SCA_KeyboardSensor::AddToTargetProp(int keyIndex)
+{
+ if (IsPrintable(keyIndex)) {
+ CValue* tprop = GetParent()->GetProperty(m_targetprop);
+
+ if (tprop) {
+ /* overwrite the old property */
+ if (IsDelete(keyIndex)) {
+ /* strip one char, if possible */
+ STR_String newprop = tprop->GetText();
+ int oldlength = newprop.Length();
+ if (oldlength >= 1 ) {
+ newprop.SetLength(oldlength - 1);
+ CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);
+ GetParent()->SetProperty(m_targetprop, newstringprop);
+ }
+ } else {
+ /* append */
+ char pchar = ToCharacter(keyIndex, IsShifted());
+ STR_String newprop = tprop->GetText() + pchar;
+ CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);
+ GetParent()->SetProperty(m_targetprop, newstringprop);
+ }
+ } else {
+ if (!IsDelete(keyIndex)) {
+ /* Make a new property. Deletes can be ignored. */
+ char pchar = ToCharacter(keyIndex, IsShifted());
+ STR_String newprop = pchar;
+ CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);
+ GetParent()->SetProperty(m_targetprop, newstringprop);
+ }
+ }
+ }
+
+}
+
+/**
+ * Determine whether this character can be printed. We cannot use
+ * the library functions here, because we need to test our own
+ * keycodes. */
+bool SCA_KeyboardSensor::IsPrintable(int keyIndex)
+{
+ /* only print
+ * - numerals: KX_ZEROKEY to KX_NINEKEY
+ * - alphas: KX_AKEY to KX_ZKEY.
+ * - specials: KX_RETKEY, KX_PADASTERKEY, KX_PADCOMMAKEY to KX_PERIODKEY,
+ * KX_TABKEY , KX_SEMICOLONKEY to KX_RIGHTBRACKETKEY,
+ * KX_PAD2 to KX_PADPLUSKEY
+ * - delete and backspace: also printable in the sense that they modify
+ * the string
+ * - retkey: should this be printable?
+ * - virgule: prints a space... don't know which key that's supposed
+ * to be...
+ */
+ if ( ((keyIndex >= SCA_IInputDevice::KX_ZEROKEY)
+ && (keyIndex <= SCA_IInputDevice::KX_NINEKEY))
+ || ((keyIndex >= SCA_IInputDevice::KX_AKEY)
+ && (keyIndex <= SCA_IInputDevice::KX_ZKEY))
+ || (keyIndex == SCA_IInputDevice::KX_SPACEKEY)
+/* || (keyIndex == KX_RETKEY) */
+ || (keyIndex == SCA_IInputDevice::KX_PADASTERKEY)
+ || (keyIndex == SCA_IInputDevice::KX_TABKEY)
+ || ((keyIndex >= SCA_IInputDevice::KX_COMMAKEY)
+ && (keyIndex <= SCA_IInputDevice::KX_PERIODKEY))
+ || ((keyIndex >= SCA_IInputDevice::KX_SEMICOLONKEY)
+ && (keyIndex <= SCA_IInputDevice::KX_RIGHTBRACKETKEY))
+ || ((keyIndex >= SCA_IInputDevice::KX_PAD2)
+ && (keyIndex <= SCA_IInputDevice::KX_PADPLUSKEY))
+ || (keyIndex == SCA_IInputDevice::KX_DELKEY)
+ || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY)
+ )
+ {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// this code looks ugly, please use an ordinary hashtable
+
+char SCA_KeyboardSensor::ToCharacter(int keyIndex, bool shifted)
+{
+ /* numerals */
+ if ( (keyIndex >= SCA_IInputDevice::KX_ZEROKEY)
+ && (keyIndex <= SCA_IInputDevice::KX_NINEKEY) ) {
+ if (shifted) {
+ char numshift[] = ")!@#$%^&*(";
+ return numshift[keyIndex - '0'];
+ } else {
+ return keyIndex - SCA_IInputDevice::KX_ZEROKEY + '0';
+ }
+ }
+
+ /* letters... always lowercase... is that desirable? */
+ if ( (keyIndex >= SCA_IInputDevice::KX_AKEY)
+ && (keyIndex <= SCA_IInputDevice::KX_ZKEY) ) {
+ if (shifted) {
+ return keyIndex - SCA_IInputDevice::KX_AKEY + 'A';
+ } else {
+ return keyIndex - SCA_IInputDevice::KX_AKEY + 'a';
+ }
+ }
+
+ if (keyIndex == SCA_IInputDevice::KX_SPACEKEY) {
+ return ' ';
+ }
+
+/* || (keyIndex == SCA_IInputDevice::KX_RETKEY) */
+
+ if (keyIndex == SCA_IInputDevice::KX_PADASTERKEY) {
+ return '*';
+ }
+
+ if (keyIndex == SCA_IInputDevice::KX_TABKEY) {
+ return '\t';
+ }
+
+ /* comma to period */
+ char commatoperiod[] = ",-.";
+ char commatoperiodshifted[] = "<_>";
+ if (keyIndex == SCA_IInputDevice::KX_COMMAKEY) {
+ if (shifted) {
+ return commatoperiodshifted[0];
+ } else {
+ return commatoperiod[0];
+ }
+ }
+ if (keyIndex == SCA_IInputDevice::KX_MINUSKEY) {
+ if (shifted) {
+ return commatoperiodshifted[1];
+ } else {
+ return commatoperiod[1];
+ }
+ }
+ if (keyIndex == SCA_IInputDevice::KX_PERIODKEY) {
+ if (shifted) {
+ return commatoperiodshifted[2];
+ } else {
+ return commatoperiod[2];
+ }
+ }
+
+ /* semicolon to rightbracket */
+ char semicolontorightbracket[] = ";\'` /\\=[]";
+ char semicolontorightbracketshifted[] = ":\"~ \?|+{}";
+ if ((keyIndex >= SCA_IInputDevice::KX_SEMICOLONKEY)
+ && (keyIndex <= SCA_IInputDevice::KX_RIGHTBRACKETKEY)) {
+ if (shifted) {
+ return semicolontorightbracketshifted[keyIndex - SCA_IInputDevice::KX_SEMICOLONKEY];
+ } else {
+ return semicolontorightbracket[keyIndex - SCA_IInputDevice::KX_SEMICOLONKEY];
+ }
+ }
+
+ /* keypad2 to padplus */
+ char pad2topadplus[] = "246813579. 0- +";
+ if ((keyIndex >= SCA_IInputDevice::KX_PAD2)
+ && (keyIndex <= SCA_IInputDevice::KX_PADPLUSKEY)) {
+ return pad2topadplus[keyIndex - SCA_IInputDevice::KX_PAD2];
+ }
+
+ return '!';
+}
+
+/**
+ * Tests whether this is a delete key.
+ */
+bool SCA_KeyboardSensor::IsDelete(int keyIndex)
+{
+ if ( (keyIndex == SCA_IInputDevice::KX_DELKEY)
+ || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY) ) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Tests whether shift is pressed
+ */
+bool SCA_KeyboardSensor::IsShifted(void)
+{
+ SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
+
+ if ( (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status
+ == SCA_InputEvent::KX_ACTIVE)
+ || (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status
+ == SCA_InputEvent::KX_JUSTACTIVATED)
+ || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status
+ == SCA_InputEvent::KX_ACTIVE)
+ || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status
+ == SCA_InputEvent::KX_JUSTACTIVATED)
+ ) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void SCA_KeyboardSensor::LogKeystrokes(void)
+{
+ SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
+ int num = inputdev->GetNumActiveEvents();
+
+ /* weird loop, this one... */
+ if (num > 0)
+ {
+
+ int index = 0;
+ /* Check on all keys whether they were pushed. This does not
+ * untangle the ordering, so don't type too fast :) */
+ for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++)
+ {
+ const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
+ if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED) //NO_INPUTSTATUS)
+ {
+ if (index < num)
+ {
+ AddToTargetProp(i);
+ index++;
+ }
+ }
+ }
+ }
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions : specific */
+/* ------------------------------------------------------------------------- */
+
+
+PyObject* SCA_KeyboardSensor::PySetAllMode(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ bool allkeys;
+
+ if (!PyArg_ParseTuple(args, "i", &allkeys))
+ {
+ return NULL;
+ }
+
+ m_bAllKeys = allkeys;
+ Py_Return
+}
+
+
+
+PyObject* SCA_KeyboardSensor::sPySetAllMode(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+// printf("sPyIsPositive\n");
+ return ((SCA_KeyboardSensor*) self)->PyIsPositive(self, args, kwds);
+}
+
+
+/** 1. GetKey : check which key this sensor looks at */
+char SCA_KeyboardSensor::GetKey_doc[] =
+"getKey()\n"
+"\tReturn the code of the key this sensor is listening to.\n" ;
+PyObject* SCA_KeyboardSensor::PyGetKey(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyInt_FromLong(m_hotkey);
+}
+
+/** 2. SetKey: change the key to look at */
+char SCA_KeyboardSensor::SetKey_doc[] =
+"setKey(keycode)\n"
+"\t- keycode: any code from GameKeys\n"
+"\tSet the key this sensor should listen to.\n" ;
+PyObject* SCA_KeyboardSensor::PySetKey(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int keyCode;
+
+ if(!PyArg_ParseTuple(args, "i", &keyCode)) {
+ return NULL;
+ }
+
+ /* Since we have symbolic constants for this in Python, we don't guard */
+ /* anything. It's up to the user to provide a sensible number. */
+ m_hotkey = keyCode;
+
+ Py_Return;
+}
+
+/** 3. GetHold1 : set the first bucky bit */
+char SCA_KeyboardSensor::GetHold1_doc[] =
+"getHold1()\n"
+"\tReturn the code of the first key modifier to the key this \n"
+"\tsensor is listening to.\n" ;
+PyObject* SCA_KeyboardSensor::PyGetHold1(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyInt_FromLong(m_qual);
+}
+
+/** 4. SetHold1: change the first bucky bit */
+char SCA_KeyboardSensor::SetHold1_doc[] =
+"setHold1(keycode)\n"
+"\t- keycode: any code from GameKeys\n"
+"\tSet the first modifier to the key this sensor should listen to.\n" ;
+PyObject* SCA_KeyboardSensor::PySetHold1(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int keyCode;
+
+ if(!PyArg_ParseTuple(args, "i", &keyCode)) {
+ return NULL;
+ }
+
+ /* Since we have symbolic constants for this in Python, we don't guard */
+ /* anything. It's up to the user to provide a sensible number. */
+ m_qual = keyCode;
+
+ Py_Return;
+}
+
+/** 5. GetHold2 : get the second bucky bit */
+char SCA_KeyboardSensor::GetHold2_doc[] =
+"getHold2()\n"
+"\tReturn the code of the second key modifier to the key this \n"
+"\tsensor is listening to.\n" ;
+PyObject* SCA_KeyboardSensor::PyGetHold2(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyInt_FromLong(m_qual2);
+}
+
+/** 6. SetHold2: change the second bucky bit */
+char SCA_KeyboardSensor::SetHold2_doc[] =
+"setHold2(keycode)\n"
+"\t- keycode: any code from GameKeys\n"
+"\tSet the first modifier to the key this sensor should listen to.\n" ;
+PyObject* SCA_KeyboardSensor::PySetHold2(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int keyCode;
+
+ if(!PyArg_ParseTuple(args, "i", &keyCode)) {
+ return NULL;
+ }
+
+ /* Since we have symbolic constants for this in Python, we don't guard */
+ /* anything. It's up to the user to provide a sensible number. */
+ m_qual2 = keyCode;
+
+ Py_Return;
+}
+
+
+char SCA_KeyboardSensor::GetPressedKeys_doc[] =
+"getPressedKeys()\n"
+"\tGet a list of pressed keys that have either been pressed, or just released this frame.\n" ;
+
+PyObject* SCA_KeyboardSensor::PyGetPressedKeys(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
+
+ int num = inputdev->GetNumJustEvents();
+ PyObject* resultlist = PyList_New(num);
+
+ if (num > 0)
+ {
+
+ int index = 0;
+
+ for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++)
+ {
+ const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
+ if ((inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED)
+ || (inevent.m_status == SCA_InputEvent::KX_JUSTRELEASED))
+ {
+ if (index < num)
+ {
+ PyObject* keypair = PyList_New(2);
+ PyList_SetItem(keypair,0,PyInt_FromLong(i));
+ PyList_SetItem(keypair,1,PyInt_FromLong(inevent.m_status));
+ PyList_SetItem(resultlist,index,keypair);
+ index++;
+ }
+ }
+ }
+ if (index>0) return resultlist;
+ }
+
+ Py_Return;
+}
+
+
+
+char SCA_KeyboardSensor::GetCurrentlyPressedKeys_doc[] =
+"getCurrentlyPressedKeys()\n"
+"\tGet a list of keys that are currently pressed.\n" ;
+
+PyObject* SCA_KeyboardSensor::PyGetCurrentlyPressedKeys(PyObject* self, PyObject* args, PyObject* kwds)
+{
+SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
+
+ int num = inputdev->GetNumActiveEvents();
+ PyObject* resultlist = PyList_New(num);
+
+ if (num > 0)
+ {
+ int index = 0;
+
+ for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++)
+ {
+ const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
+ if ( (inevent.m_status == SCA_InputEvent::KX_ACTIVE)
+ || (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED))
+ {
+ if (index < num)
+ {
+ PyObject* keypair = PyList_New(2);
+ PyList_SetItem(keypair,0,PyInt_FromLong(i));
+ PyList_SetItem(keypair,1,PyInt_FromLong(inevent.m_status));
+ PyList_SetItem(resultlist,index,keypair);
+ index++;
+ }
+ }
+ }
+
+ /* why?*/
+ if (index > 0) return resultlist;
+ }
+
+ Py_Return;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions : integration hooks */
+/* ------------------------------------------------------------------------- */
+
+PyTypeObject SCA_KeyboardSensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_KeyboardSensor",
+ sizeof(SCA_KeyboardSensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_KeyboardSensor::Parents[] = {
+ &SCA_KeyboardSensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef SCA_KeyboardSensor::Methods[] = {
+ {"getKey", (PyCFunction) SCA_KeyboardSensor::sPyGetKey, METH_VARARGS, GetKey_doc},
+ {"setKey", (PyCFunction) SCA_KeyboardSensor::sPySetKey, METH_VARARGS, SetKey_doc},
+ {"getHold1", (PyCFunction) SCA_KeyboardSensor::sPyGetHold1, METH_VARARGS, GetHold1_doc},
+ {"setHold1", (PyCFunction) SCA_KeyboardSensor::sPySetHold1, METH_VARARGS, SetHold1_doc},
+ {"getHold2", (PyCFunction) SCA_KeyboardSensor::sPyGetHold2, METH_VARARGS, GetHold2_doc},
+ {"setHold2", (PyCFunction) SCA_KeyboardSensor::sPySetHold2, METH_VARARGS, SetHold2_doc},
+// {"getUseAllKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetUseAllKeys, METH_VARARGS, GetUseAllKeys_doc},
+// {"setUseAllKeys", (PyCFunction) SCA_KeyboardSensor::sPySetUseAllKeys, METH_VARARGS, SetUseAllKeys_doc},
+ {"getPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetPressedKeys, METH_VARARGS, GetPressedKeys_doc},
+ {"getCurrentlyPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetCurrentlyPressedKeys, METH_VARARGS, GetCurrentlyPressedKeys_doc},
+// {"getKeyEvents", (PyCFunction) SCA_KeyboardSensor::sPyGetKeyEvents, METH_VARARGS, GetKeyEvents_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject*
+SCA_KeyboardSensor::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_ISensor);
+}
+
diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.h b/source/gameengine/GameLogic/SCA_KeyboardSensor.h
new file mode 100644
index 00000000000..f4a3d7e47b5
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.h
@@ -0,0 +1,159 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Sensor for keyboard input
+ */
+
+#ifndef __KX_KEYBOARDSENSOR
+#define __KX_KEYBOARDSENSOR
+
+#include "SCA_ISensor.h"
+#include "BoolValue.h"
+#include <list>
+
+/**
+ * The keyboard sensor listens to the keyboard, and passes on events
+ * on selected keystrokes. It has an alternate mode in which it logs
+ * keypresses to a property. Note that these modes are not mutually
+ * exclusive. */
+class SCA_KeyboardSensor : public SCA_ISensor
+{
+ Py_Header;
+ class SCA_KeyboardManager* m_pKeyboardMgr;
+
+
+ /**
+ * the key this sensor is sensing for
+ */
+ int m_hotkey;
+ short int m_qual,m_qual2;
+ short int m_val;
+ /**
+ * If this toggle is true, all incoming key events generate a
+ * response.
+ */
+ bool m_bAllKeys;
+
+ /**
+ * The name of the property to which logged text is appended. If
+ * this property is not defined, no logging takes place.
+ */
+ STR_String m_targetprop;
+ /**
+ * The property that indicates whether or not to log text when in
+ * loggin mode. If the property equals 0, no loggin is done. For
+ * all other values, logging is active. Logging can only become
+ * active if there is a property to log to. Logging is independant
+ * from hotkey settings. */
+ STR_String m_toggleprop;
+
+ /**
+ * Log the keystrokes from the current input buffer.
+ */
+ void LogKeystrokes(void);
+
+ /**
+ * Adds this key-code to the target prop.
+ */
+ void AddToTargetProp(int keyIndex);
+
+ /**
+ * Determine whether this character can be printed. We cannot use
+ * the library functions here, because we need to test our own
+ * keycodes. */
+ bool IsPrintable(int keyIndex);
+
+ /**
+ * Transform keycodes to something printable.
+ */
+ char ToCharacter(int keyIndex, bool shifted);
+
+ /**
+ * Tests whether this is a delete key.
+ */
+ bool IsDelete(int keyIndex);
+
+ /**
+ * Tests whether shift is pressed.
+ */
+ bool IsShifted(void);
+
+public:
+ SCA_KeyboardSensor(class SCA_KeyboardManager* keybdmgr,
+ short int hotkey,
+ short int qual,
+ short int qual2,
+ bool bAllKeys,
+ const STR_String& targetProp,
+ const STR_String& toggleProp,
+ SCA_IObject* gameobj,
+ PyTypeObject* T=&Type );
+ virtual ~SCA_KeyboardSensor();
+ virtual CValue* GetReplica();
+
+ short int GetHotkey();
+ virtual bool Evaluate(CValue* event);
+ virtual bool IsPositiveTrigger();
+ bool TriggerOnAllKeys();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+
+ PyObject* PySetAllMode(PyObject* self,
+ PyObject* args,
+ PyObject* kwds);
+ static PyObject* sPySetAllMode(PyObject* self,
+ PyObject* args,
+ PyObject* kwds);
+
+ /** 1. GetKey : check which key this sensor looks at */
+ KX_PYMETHOD_DOC(SCA_KeyboardSensor,GetKey);
+ /** 2. SetKey: change the key to look at */
+ KX_PYMETHOD_DOC(SCA_KeyboardSensor,SetKey);
+ /** 3. GetHold1 : set the first bucky bit */
+ KX_PYMETHOD_DOC(SCA_KeyboardSensor,GetHold1);
+ /** 4. SetHold1: change the first bucky bit */
+ KX_PYMETHOD_DOC(SCA_KeyboardSensor,SetHold1);
+ /** 5. GetHold2 : set the second bucky bit */
+ KX_PYMETHOD_DOC(SCA_KeyboardSensor,GetHold2);
+ /** 6. SetHold2: change the second bucky bit */
+ KX_PYMETHOD_DOC(SCA_KeyboardSensor,SetHold2);
+ /** 9. GetPressedKeys: */
+ KX_PYMETHOD_DOC(SCA_KeyboardSensor,GetPressedKeys);
+ /** 9. GetCurrrentlyPressedKeys: */
+ KX_PYMETHOD_DOC(SCA_KeyboardSensor,GetCurrentlyPressedKeys);
+};
+
+#endif //__KX_KEYBOARDSENSOR
+
diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp
new file mode 100644
index 00000000000..8b79703a6fc
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp
@@ -0,0 +1,487 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Regulates the top-level logic behaviour for one scene.
+ */
+#include "Value.h"
+#include "SCA_LogicManager.h"
+#include "SCA_ISensor.h"
+#include "SCA_IController.h"
+#include "SCA_IActuator.h"
+#include "SCA_EventManager.h"
+#include <set>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+SCA_LogicManager::SCA_LogicManager()
+{
+}
+
+
+
+SCA_LogicManager::~SCA_LogicManager()
+{
+ int numgameobj = m_mapStringToGameObjects.size();
+ for (int i = 0; i < numgameobj; i++)
+ {
+ CValue** gameobjptr = m_mapStringToGameObjects.at(i);
+ assert(gameobjptr);
+ if (gameobjptr)
+ (*gameobjptr)->Release();
+
+ }
+ /*for (int i=0;i<m_sensorcontrollermap.size();i++)
+ {
+ vector<SCA_IController*>* controllerarray = *(m_sensorcontrollermap[i]);
+ delete controllerarray;
+ }
+ */
+ for (vector<SCA_EventManager*>::iterator it = m_eventmanagers.begin();!(it==m_eventmanagers.end());it++)
+ {
+ delete (*it);
+ }
+ m_eventmanagers.clear();
+ m_sensorcontrollermapje.clear();
+}
+
+
+/*
+// this kind of fixes bug 398 but breakes games, so better leave it out for now.
+// a removed object's gameobject (and logicbricks and stuff) didn't get released
+// because it was still in the m_mapStringToGameObjects map.
+void SCA_LogicManager::RemoveGameObject(const STR_String& gameobjname)
+{
+ int numgameobj = m_mapStringToGameObjects.size();
+ for (int i = 0; i < numgameobj; i++)
+ {
+ CValue** gameobjptr = m_mapStringToGameObjects.at(i);
+ assert(gameobjptr);
+
+ if (gameobjptr)
+ {
+ if ((*gameobjptr)->GetName() == gameobjname)
+ (*gameobjptr)->Release();
+ }
+ }
+
+ m_mapStringToGameObjects.remove(gameobjname);
+}
+*/
+
+
+void SCA_LogicManager::RegisterEventManager(SCA_EventManager* eventmgr)
+{
+ m_eventmanagers.push_back(eventmgr);
+}
+
+
+
+void SCA_LogicManager::RegisterGameObjectName(const STR_String& gameobjname,
+ CValue* gameobj)
+{
+ STR_HashedString mn = gameobjname;
+ m_mapStringToGameObjects.insert(mn,gameobj);
+}
+
+
+
+void SCA_LogicManager::RegisterGameMeshName(const STR_String& gamemeshname, void* blendobj)
+{
+ STR_HashedString mn = gamemeshname;
+ m_map_gamemeshname_to_blendobj.insert(mn, blendobj);
+}
+
+
+
+void SCA_LogicManager::RegisterGameObj(CValue* gameobj, void* blendobj)
+{
+ m_map_gameobj_to_blendobj.insert(CHashedPtr(gameobj), blendobj);
+}
+
+
+
+CValue* SCA_LogicManager::GetGameObjectByName(const STR_String& gameobjname)
+{
+ STR_HashedString mn = "OB"+gameobjname;
+ CValue** gameptr = m_mapStringToGameObjects[mn];
+
+ if (gameptr)
+ return *gameptr;
+
+ return NULL;
+}
+
+
+void* SCA_LogicManager::FindBlendObjByGameObj(CValue* gameobject)
+{
+ void **obp= m_map_gameobj_to_blendobj[CHashedPtr(gameobject)];
+ return obp?*obp:NULL;
+}
+
+
+
+void* SCA_LogicManager::FindBlendObjByGameMeshName(const STR_String& gamemeshname)
+{
+ STR_HashedString mn = gamemeshname;
+ void **obp= m_map_gamemeshname_to_blendobj[mn];
+ return obp?*obp:NULL;
+}
+
+
+
+void SCA_LogicManager::RemoveSensor(SCA_ISensor* sensor)
+{
+ m_sensorcontrollermapje.erase(sensor);
+
+ for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin();
+ !(ie==m_eventmanagers.end());ie++)
+ {
+ (*ie)->RemoveSensor(sensor);
+ }
+}
+
+
+
+void SCA_LogicManager::RemoveDestroyedActuator(SCA_IActuator* actuator)
+{
+ m_removedActuators.push_back(SmartActuatorPtr(actuator,0));
+ // take care that no controller can use this actuator again !
+
+ std::map<SCA_ISensor*,controllerlist>::const_iterator sit;
+ for (sit = m_sensorcontrollermapje.begin();!(sit==m_sensorcontrollermapje.end());++sit)
+ {
+ controllerlist contlist = (*sit).second;
+ for (list<SCA_IController*>::const_iterator c= contlist.begin();!(c==contlist.end());c++)
+ {
+ (*c)->UnlinkActuator(actuator);
+ }
+ }
+}
+
+
+
+void SCA_LogicManager::RegisterToSensor(SCA_IController* controller,SCA_ISensor* sensor)
+{
+ m_sensorcontrollermapje[sensor].push_back(controller);
+ controller->LinkToSensor(sensor);
+}
+
+
+
+void SCA_LogicManager::RegisterToActuator(SCA_IController* controller,SCA_IActuator* actua)
+{
+ controller->LinkToActuator(actua);
+}
+
+
+
+void SCA_LogicManager::BeginFrame(double curtime, double fixedtime)
+{
+ for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin(); !(ie==m_eventmanagers.end()); ie++)
+ (*ie)->NextFrame(curtime, fixedtime);
+
+ // for this frame, look up for activated sensors, and build the collection of triggered controllers
+ // int numsensors = this->m_activatedsensors.size(); /*unused*/
+
+ set<SmartControllerPtr> triggeredControllerSet;
+
+ for (vector<SCA_ISensor*>::const_iterator is=m_activatedsensors.begin();
+ !(is==m_activatedsensors.end());is++)
+ {
+ SCA_ISensor* sensor = *is;
+ controllerlist contlist = m_sensorcontrollermapje[sensor];
+ for (list<SCA_IController*>::const_iterator c= contlist.begin();
+ !(c==contlist.end());c++)
+ {
+ SCA_IController* contr = *c;//controllerarray->at(c);
+ triggeredControllerSet.insert(SmartControllerPtr(contr,0));
+ }
+ //sensor->SetActive(false);
+ }
+
+
+ // int numtriggered = triggeredControllerSet.size(); /*unused*/
+ for (set<SmartControllerPtr>::iterator tit=triggeredControllerSet.begin();
+ !(tit==triggeredControllerSet.end());tit++)
+ {
+ (*tit)->Trigger(this);
+ }
+ triggeredControllerSet.clear();
+}
+
+
+
+void SCA_LogicManager::UpdateFrame(double curtime, bool frame)
+{
+ vector<SmartActuatorPtr>::iterator ra;
+ for (ra = m_removedActuators.begin(); !(ra == m_removedActuators.end()); ra++)
+ {
+ m_activeActuators.erase(*ra);
+ (*ra)->SetActive(false);
+ }
+ m_removedActuators.clear();
+
+ for (set<SmartActuatorPtr>::iterator ia = m_activeActuators.begin();!(ia==m_activeActuators.end());ia++)
+ {
+ //SCA_IActuator* actua = *ia;
+ if (!(*ia)->Update(curtime, frame))
+ {
+ //*ia = m_activeactuators.back();
+ m_removedActuators.push_back(*ia);
+
+ (*ia)->SetActive(false);
+ //m_activeactuators.pop_back();
+ }
+ }
+
+ for ( ra = m_removedActuators.begin(); !(ra == m_removedActuators.end()); ra++)
+ {
+ m_activeActuators.erase(*ra);
+ (*ra)->SetActive(false);
+ }
+ m_removedActuators.clear();
+}
+
+
+
+void* SCA_LogicManager::GetActionByName (const STR_String& actname)
+{
+ STR_HashedString an = "AC"+actname;
+ void** actptr = m_mapStringToActions[an];
+
+ if (actptr)
+ return *actptr;
+
+ return NULL;
+}
+
+
+
+void* SCA_LogicManager::GetMeshByName(const STR_String& meshname)
+{
+ STR_HashedString mn = "ME"+meshname;
+ void** meshptr = m_mapStringToMeshes[mn];
+
+ if (meshptr)
+ return *meshptr;
+
+ return NULL;
+}
+
+
+
+void SCA_LogicManager::RegisterMeshName(const STR_String& meshname,void* mesh)
+{
+ STR_HashedString mn = meshname;
+ m_mapStringToMeshes.insert(mn,mesh);
+}
+
+
+
+void SCA_LogicManager::RegisterActionName(const STR_String& actname,void* action)
+{
+ STR_HashedString an = actname;
+ m_mapStringToActions.insert(an, action);
+}
+
+
+
+void SCA_LogicManager::EndFrame()
+{
+ for (vector<SCA_ISensor*>::const_iterator is=m_activatedsensors.begin();
+ !(is==m_activatedsensors.end());is++)
+ {
+ SCA_ISensor* sensor = *is;
+ sensor->SetActive(false);
+ }
+ m_activatedsensors.clear();
+
+ for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin();
+ !(ie==m_eventmanagers.end());ie++)
+ {
+ (*ie)->EndFrame();
+ }
+
+
+}
+
+
+
+void SCA_LogicManager::AddActivatedSensor(SCA_ISensor* sensor)
+{
+ // each frame, only add sensor once, and to avoid a seek, or bloated container
+ // hold a flag in each sensor, with the 'framenr'
+ if (!sensor->IsActive())
+ {
+ sensor->SetActive(true);
+ m_activatedsensors.push_back(sensor);
+ }
+}
+
+
+
+void SCA_LogicManager::AddActiveActuator(SCA_IActuator* actua,CValue* event)
+{
+ if (!actua->IsActive())
+ {
+ actua->SetActive(true);
+ m_activeActuators.insert(SmartActuatorPtr(actua,0));
+ }
+ actua->AddEvent(event->AddRef());
+}
+
+
+
+SCA_EventManager* SCA_LogicManager::FindEventManager(int eventmgrtype)
+{
+ // find an eventmanager of a certain type
+ SCA_EventManager* eventmgr = NULL;
+
+ for (vector<SCA_EventManager*>::const_iterator i=
+ m_eventmanagers.begin();!(i==m_eventmanagers.end());i++)
+ {
+ SCA_EventManager* emgr = *i;
+ if (emgr->GetType() == eventmgrtype)
+ {
+ eventmgr = emgr;
+ break;
+ }
+ }
+ return eventmgr;
+}
+
+
+
+SmartActuatorPtr::SmartActuatorPtr(const SmartActuatorPtr& other)
+{
+ this->m_actuator = other.m_actuator;
+ this->m_actuator->AddRef();
+}
+
+
+
+SmartActuatorPtr::SmartActuatorPtr(SCA_IActuator* actua,int dummy)
+: m_actuator(actua)
+{
+ actua->AddRef();
+}
+
+
+
+SmartActuatorPtr::~SmartActuatorPtr()
+{
+ m_actuator->Release();
+}
+
+
+
+bool SmartActuatorPtr::operator <(const SmartActuatorPtr& other) const
+{
+
+ return m_actuator->LessComparedTo(*other);
+}
+
+
+
+bool SmartActuatorPtr::operator ==(const SmartActuatorPtr& other) const
+{
+ bool result2 = other->LessComparedTo(m_actuator);
+ return (m_actuator->LessComparedTo(*other) && result2);
+}
+
+
+
+SCA_IActuator* SmartActuatorPtr::operator->() const
+{
+ return m_actuator;
+}
+
+
+
+SCA_IActuator* SmartActuatorPtr::operator*() const
+{
+ return m_actuator;
+}
+
+
+
+SmartControllerPtr::SmartControllerPtr(const SmartControllerPtr& copy)
+{
+ this->m_controller = copy.m_controller;
+ this->m_controller->AddRef();
+}
+
+
+
+SmartControllerPtr::SmartControllerPtr(SCA_IController* contr,int dummy)
+: m_controller(contr)
+{
+ m_controller->AddRef();
+}
+
+
+
+SmartControllerPtr::~SmartControllerPtr()
+{
+ m_controller->Release();
+}
+
+
+
+bool SmartControllerPtr::operator <(const SmartControllerPtr& other) const
+{
+ return m_controller->LessComparedTo(*other);
+}
+
+
+
+bool SmartControllerPtr::operator ==(const SmartControllerPtr& other) const
+{
+ return (m_controller->LessComparedTo(*other) && other->LessComparedTo(m_controller));
+}
+
+
+
+SCA_IController* SmartControllerPtr::operator->() const
+{
+ return m_controller;
+}
+
+
+
+SCA_IController* SmartControllerPtr::operator*() const
+{
+ return m_controller;
+}
+
+
diff --git a/source/gameengine/GameLogic/SCA_LogicManager.h b/source/gameengine/GameLogic/SCA_LogicManager.h
new file mode 100644
index 00000000000..2eee2129665
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_LogicManager.h
@@ -0,0 +1,163 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Regulates the top-level logic behaviour for one scene.
+ */
+#ifndef __KX_LOGICMANAGER
+#define __KX_LOGICMANAGER
+
+#ifdef WIN32
+#pragma warning (disable:4786)
+#endif
+
+#include <vector>
+//#include "GEN_Map.h"
+#include <set>
+#include <map>
+#include <list>
+
+#include "GEN_Map.h"
+#include "STR_HashedString.h"
+#include "Value.h"
+
+#include "KX_HashedPtr.h"
+
+using namespace std;
+typedef list<class SCA_IController*> controllerlist;
+
+/**
+ * This manager handles sensor, controllers and actuators.
+ * logic executes each frame the following way:
+ * find triggering sensors
+ * build list of controllers that are triggered by these triggering sensors
+ * process all triggered controllers
+ * during this phase actuators can be added to the active actuator list
+ * process all active actuators
+ * clear triggering sensors
+ * clear triggered controllers
+ * (actuators may be active during a longer timeframe)
+*/
+
+#include "SCA_ILogicBrick.h"
+
+// todo: make this into a template, but first I want to think about what exactly to put in
+class SmartActuatorPtr
+{
+ SCA_IActuator* m_actuator;
+public:
+ SmartActuatorPtr(SCA_IActuator* actua,int dummy);
+ SmartActuatorPtr(const SmartActuatorPtr& other);
+ virtual ~SmartActuatorPtr();
+ bool operator <(const SmartActuatorPtr& other) const;
+ bool operator ==(const SmartActuatorPtr& other) const;
+ SCA_IActuator* operator->() const;
+ SCA_IActuator* operator*() const;
+
+};
+
+class SmartControllerPtr
+{
+ SCA_IController* m_controller;
+public:
+ SmartControllerPtr(const SmartControllerPtr& copy);
+ SmartControllerPtr(SCA_IController* contr,int dummy);
+ virtual ~SmartControllerPtr();
+ bool operator <(const SmartControllerPtr& other) const;
+ bool operator ==(const SmartControllerPtr& other) const;
+ SCA_IController* operator->() const;
+ SCA_IController* operator*() const;
+
+};
+
+class SCA_LogicManager
+{
+ vector<class SCA_EventManager*> m_eventmanagers;
+
+ vector<class SCA_ISensor*> m_activatedsensors;
+ set<class SmartActuatorPtr> m_activeActuators;
+
+ map<SCA_ISensor*,controllerlist > m_sensorcontrollermapje;
+
+ // need to find better way for this
+ // also known as FactoryManager...
+ GEN_Map<STR_HashedString,CValue*> m_mapStringToGameObjects;
+ GEN_Map<STR_HashedString,void*> m_mapStringToMeshes;
+ GEN_Map<STR_HashedString,void*> m_mapStringToActions;
+
+ GEN_Map<STR_HashedString,void*> m_map_gamemeshname_to_blendobj;
+ GEN_Map<CHashedPtr,void*> m_map_gameobj_to_blendobj;
+
+ vector<SmartActuatorPtr> m_removedActuators;
+public:
+ SCA_LogicManager();
+ virtual ~SCA_LogicManager();
+ //void SetKeyboardManager(SCA_KeyboardManager* keyboardmgr) { m_keyboardmgr=keyboardmgr;}
+ void RegisterEventManager(SCA_EventManager* eventmgr);
+ void RegisterToSensor(SCA_IController* controller,
+ class SCA_ISensor* sensor);
+ void RegisterToActuator(SCA_IController* controller,
+ class SCA_IActuator* actuator);
+
+ void BeginFrame(double curtime, double fixedtime);
+ void UpdateFrame(double curtime, bool frame);
+ void EndFrame();
+ void AddActivatedSensor(SCA_ISensor* sensor);
+ void AddActiveActuator(SCA_IActuator* sensor,class CValue* event);
+ SCA_EventManager* FindEventManager(int eventmgrtype);
+
+ void RemoveGameObject(const STR_String& gameobjname);
+
+ /**
+ * remove Logic Bricks from the running logicmanager
+ */
+ void RemoveSensor(SCA_ISensor* sensor);
+ void RemoveController(SCA_IController* controller);
+ void RemoveDestroyedActuator(SCA_IActuator* actuator);
+
+
+ // for the scripting... needs a FactoryManager later (if we would have time... ;)
+ void RegisterMeshName(const STR_String& meshname,void* mesh);
+ void RegisterActionName(const STR_String& actname,void* action);
+
+ void* GetActionByName (const STR_String& actname);
+ void* GetMeshByName(const STR_String& meshname);
+
+ void RegisterGameObjectName(const STR_String& gameobjname,CValue* gameobj);
+ class CValue* GetGameObjectByName(const STR_String& gameobjname);
+
+ void RegisterGameMeshName(const STR_String& gamemeshname, void* blendobj);
+ void* FindBlendObjByGameMeshName(const STR_String& gamemeshname);
+
+ void RegisterGameObj(CValue* gameobj, void* blendobj);
+ void* FindBlendObjByGameObj(CValue* gameobj);
+};
+
+#endif //__KX_LOGICMANAGER
+
diff --git a/source/gameengine/GameLogic/SCA_MouseManager.cpp b/source/gameengine/GameLogic/SCA_MouseManager.cpp
new file mode 100644
index 00000000000..e4d54c94395
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_MouseManager.cpp
@@ -0,0 +1,120 @@
+/**
+ * Manager for mouse events
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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
+// This warning tells us about truncation of __long__ stl-generated names.
+// It can occasionally cause DevStudio to have internal compiler warnings.
+#pragma warning( disable : 4786 )
+#endif
+
+#include "BoolValue.h"
+#include "SCA_MouseManager.h"
+#include "SCA_MouseSensor.h"
+#include "IntValue.h"
+
+
+SCA_MouseManager::SCA_MouseManager(SCA_LogicManager* logicmgr,
+ SCA_IInputDevice* mousedev)
+ : SCA_EventManager(MOUSE_EVENTMGR),
+ m_mousedevice (mousedev),
+ m_logicmanager(logicmgr)
+{
+ m_xpos = 0;
+ m_ypos = 0;
+}
+
+
+
+SCA_MouseManager::~SCA_MouseManager()
+{
+}
+
+
+
+SCA_IInputDevice* SCA_MouseManager::GetInputDevice()
+{
+ return m_mousedevice;
+}
+
+
+
+void SCA_MouseManager::NextFrame()
+{
+ if (m_mousedevice)
+ {
+ for (unsigned int i = 0; i < m_sensors.size(); i++)
+ {
+ SCA_MouseSensor* mousesensor = (SCA_MouseSensor*) m_sensors[i];
+ // (0,0) is the Upper Left corner in our local window
+ // coordinates
+ if (!mousesensor->IsSuspended())
+ {
+ const SCA_InputEvent& event =
+ m_mousedevice->GetEventValue(SCA_IInputDevice::KX_MOUSEX);
+ int mx = event.m_eventval;
+ const SCA_InputEvent& event2 =
+ m_mousedevice->GetEventValue(SCA_IInputDevice::KX_MOUSEY);
+ int my = event2.m_eventval;
+
+ mousesensor->setX(mx);
+ mousesensor->setY(my);
+
+ mousesensor->Activate(m_logicmanager,NULL);
+ }
+ }
+ }
+}
+
+
+
+void SCA_MouseManager::RegisterSensor(SCA_ISensor* keysensor)
+{
+ m_sensors.push_back(keysensor);
+}
+
+
+
+bool SCA_MouseManager::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode)
+{
+ /* We should guard for non-mouse events maybe? A rather silly side */
+ /* effect here is that position-change events are considered presses as */
+ /* well. */
+
+ return m_mousedevice->IsPressed(inputcode);
+}
diff --git a/source/gameengine/GameLogic/SCA_MouseManager.h b/source/gameengine/GameLogic/SCA_MouseManager.h
new file mode 100644
index 00000000000..e98405b1b7d
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_MouseManager.h
@@ -0,0 +1,73 @@
+/**
+ * Manager for mouse events
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_MOUSEMANAGER
+#define __KX_MOUSEMANAGER
+
+
+#include "SCA_EventManager.h"
+
+#include <vector>
+
+using namespace std;
+
+#include "SCA_IInputDevice.h"
+
+
+class SCA_MouseManager : public SCA_EventManager
+{
+
+ class SCA_IInputDevice* m_mousedevice;
+ class SCA_LogicManager* m_logicmanager;
+
+ unsigned short m_xpos; // Cached location of the mouse pointer
+ unsigned short m_ypos;
+
+public:
+ SCA_MouseManager(class SCA_LogicManager* logicmgr,class SCA_IInputDevice* mousedev);
+ virtual ~SCA_MouseManager();
+
+ /**
+ * Checks whether a mouse button is depressed. Ignores requests on non-
+ * mouse related evenst. Can also flag mouse movement.
+ */
+ bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode);
+ virtual void NextFrame();
+ virtual void RegisterSensor(class SCA_ISensor* sensor);
+ SCA_IInputDevice* GetInputDevice();
+};
+
+#endif //__KX_MOUSEMANAGER
+
diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.cpp b/source/gameengine/GameLogic/SCA_MouseSensor.cpp
new file mode 100644
index 00000000000..fda641cfc96
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_MouseSensor.cpp
@@ -0,0 +1,285 @@
+/**
+ * Sensor for mouse input
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_MouseSensor.h"
+#include "SCA_EventManager.h"
+#include "SCA_MouseManager.h"
+#include "SCA_LogicManager.h"
+#include "SCA_IInputDevice.h"
+#include "ConstExpr.h"
+#include <iostream>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+SCA_MouseSensor::SCA_MouseSensor(SCA_MouseManager* eventmgr,
+ int startx,int starty,
+ short int mousemode,
+ SCA_IObject* gameobj,
+ PyTypeObject* T)
+ : SCA_ISensor(gameobj,eventmgr, T),
+ m_pMouseMgr(eventmgr),
+ m_x(startx),
+ m_y(starty)
+{
+ m_mousemode = mousemode;
+ m_triggermode = true;
+ m_val = 0; /* stores the latest attribute */
+
+ switch (m_mousemode) {
+ case KX_MOUSESENSORMODE_LEFTBUTTON:
+ m_hotkey = SCA_IInputDevice::KX_LEFTMOUSE;
+ break;
+ case KX_MOUSESENSORMODE_MIDDLEBUTTON:
+ m_hotkey = SCA_IInputDevice::KX_MIDDLEMOUSE;
+ break;
+ case KX_MOUSESENSORMODE_RIGHTBUTTON:
+ m_hotkey = SCA_IInputDevice::KX_RIGHTMOUSE;
+ break;
+ case KX_MOUSESENSORMODE_WHEELUP:
+ m_hotkey = SCA_IInputDevice::KX_WHEELUPMOUSE;
+ break;
+ case KX_MOUSESENSORMODE_WHEELDOWN:
+ m_hotkey = SCA_IInputDevice::KX_WHEELDOWNMOUSE;
+ break;
+ default:
+ ; /* ignore, no hotkey */
+ }
+
+}
+
+SCA_MouseSensor::~SCA_MouseSensor()
+{
+ /* Nothing to be done here. */
+}
+
+
+
+CValue* SCA_MouseSensor::GetReplica()
+{
+ CValue* replica = new SCA_MouseSensor(*this);
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+bool SCA_MouseSensor::IsPositiveTrigger()
+{
+ bool result = (m_val != 0);
+ if (m_invert)
+ result = !result;
+
+ return result;
+}
+
+
+
+short int SCA_MouseSensor::GetModeKey()
+{
+ return m_mousemode;
+}
+
+
+
+SCA_IInputDevice::KX_EnumInputs SCA_MouseSensor::GetHotKey()
+{
+ return m_hotkey;
+}
+
+
+
+bool SCA_MouseSensor::Evaluate(CValue* event)
+{
+ bool result = false;
+ SCA_IInputDevice* mousedev = m_pMouseMgr->GetInputDevice();
+
+
+
+// SCA_ILogicBrick::RegisterEvent(event);
+// if (m_mousemode == KX_MOUSESENSORMODE_MOVEMENT) cout << "\nChecking for movement...";
+//CValue* val = event->GetProperty("val");
+
+ /* both MOUSEX and MOUSEY. Treat all of these as key-presses. */
+ /* So, treat KX_MOUSESENSORMODE_POSITION as */
+ /* KX_MOUSESENSORMODE_POSITIONX || KX_MOUSESENSORMODE_POSITIONY */
+
+ switch (m_mousemode) {
+ case KX_MOUSESENSORMODE_LEFTBUTTON:
+ case KX_MOUSESENSORMODE_MIDDLEBUTTON:
+ case KX_MOUSESENSORMODE_RIGHTBUTTON:
+ case KX_MOUSESENSORMODE_WHEELUP:
+ case KX_MOUSESENSORMODE_WHEELDOWN:
+ {
+ const SCA_InputEvent& event = mousedev->GetEventValue(m_hotkey);
+ if (event.m_status == SCA_InputEvent::KX_JUSTACTIVATED)
+ {
+ m_val = 1;
+ result = true;
+ } else
+ {
+ if (event.m_status == SCA_InputEvent::KX_JUSTRELEASED)
+ {
+ m_val = 0;
+ result = true;
+ }
+ }
+ break;
+ }
+ case KX_MOUSESENSORMODE_MOVEMENT:
+
+ {
+ const SCA_InputEvent& eventX = mousedev->GetEventValue(SCA_IInputDevice::KX_MOUSEX);
+ const SCA_InputEvent& eventY = mousedev->GetEventValue(SCA_IInputDevice::KX_MOUSEY);
+
+ if (eventX.m_status == SCA_InputEvent::KX_JUSTACTIVATED ||
+ eventY.m_status == SCA_InputEvent::KX_JUSTACTIVATED ||
+ eventX.m_status == SCA_InputEvent::KX_ACTIVE ||
+ eventY.m_status == SCA_InputEvent::KX_ACTIVE)
+
+ {
+ m_val = 1;
+ result = true;
+ } else
+ {
+ if (eventX.m_status == SCA_InputEvent::KX_JUSTRELEASED ||
+ eventY.m_status == SCA_InputEvent::KX_JUSTRELEASED )
+ {
+ m_val = 0;
+ result = true;
+ }
+ }
+ break;
+ }
+ default:
+ ; /* error */
+ }
+
+ return result;
+}
+
+void SCA_MouseSensor::setX(short x)
+{
+ m_x = x;
+}
+
+void SCA_MouseSensor::setY(short y)
+{
+ m_y = y;
+}
+
+bool SCA_MouseSensor::isValid(SCA_MouseSensor::KX_MOUSESENSORMODE m)
+{
+ bool res = false;
+
+ res = ((m > KX_MOUSESENSORMODE_NODEF) && (m < KX_MOUSESENSORMODE_MAX));
+
+ return res;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject SCA_MouseSensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_MouseSensor",
+ sizeof(SCA_MouseSensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_MouseSensor::Parents[] = {
+ &SCA_MouseSensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef SCA_MouseSensor::Methods[] = {
+ {"getXPosition", (PyCFunction) SCA_MouseSensor::sPyGetXPosition, METH_VARARGS, GetXPosition_doc},
+ {"getYPosition", (PyCFunction) SCA_MouseSensor::sPyGetYPosition, METH_VARARGS, GetYPosition_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* SCA_MouseSensor::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_ISensor);
+}
+
+/* get x position ---------------------------------------------------------- */
+char SCA_MouseSensor::GetXPosition_doc[] =
+"getXPosition\n"
+"\tReturns the x-coordinate of the mouse sensor, in frame coordinates.\n"
+"\tThe lower-left corner is the origin. The coordinate is given in\n"
+"\tpixels\n";
+PyObject* SCA_MouseSensor::PyGetXPosition(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return PyInt_FromLong(m_x);
+}
+
+/* get y position ---------------------------------------------------------- */
+char SCA_MouseSensor::GetYPosition_doc[] =
+"getYPosition\n"
+"\tReturns the y-coordinate of the mouse sensor, in frame coordinates.\n"
+"\tThe lower-left corner is the origin. The coordinate is given in\n"
+"\tpixels\n";
+PyObject* SCA_MouseSensor::PyGetYPosition(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return PyInt_FromLong(m_y);
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.h b/source/gameengine/GameLogic/SCA_MouseSensor.h
new file mode 100644
index 00000000000..e8a0d0db78b
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_MouseSensor.h
@@ -0,0 +1,123 @@
+/**
+ * Senses mouse events
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_MOUSESENSOR
+#define __KX_MOUSESENSOR
+
+#include "SCA_ISensor.h"
+#include "BoolValue.h"
+#include "SCA_IInputDevice.h"
+
+class SCA_MouseSensor : public SCA_ISensor
+{
+ Py_Header;
+ class SCA_MouseManager* m_pMouseMgr;
+
+ /**
+ * Use SCA_IInputDevice values to encode the mouse mode for now.
+ */
+ short int m_mousemode;
+ /**
+ * Triggermode true means all mouse events trigger. Useful mainly
+ * for button presses.
+ */
+ bool m_triggermode;
+ /**
+ * Remember the last state update
+ */
+ int m_val;
+
+ SCA_IInputDevice::KX_EnumInputs m_hotkey;
+
+ /**
+ * valid x coordinate
+ */
+ short m_x;
+
+ /**
+ * valid y coordinate
+ */
+ short m_y;
+
+ public:
+ /**
+ * Allowable modes for the trigger status of the mouse sensor.
+ */
+ enum KX_MOUSESENSORMODE {
+ KX_MOUSESENSORMODE_NODEF = 0,
+ KX_MOUSESENSORMODE_LEFTBUTTON,
+ KX_MOUSESENSORMODE_MIDDLEBUTTON,
+ KX_MOUSESENSORMODE_RIGHTBUTTON,
+ KX_MOUSESENSORMODE_WHEELUP,
+ KX_MOUSESENSORMODE_WHEELDOWN,
+ KX_MOUSESENSORMODE_POSITION,
+ KX_MOUSESENSORMODE_POSITIONX,
+ KX_MOUSESENSORMODE_POSITIONY,
+ KX_MOUSESENSORMODE_MOVEMENT,
+ KX_MOUSESENSORMODE_MAX
+ };
+
+ bool isValid(KX_MOUSESENSORMODE);
+
+ SCA_MouseSensor(class SCA_MouseManager* keybdmgr,
+ int startx,int starty,
+ short int mousemode,
+ SCA_IObject* gameobj,
+ PyTypeObject* T=&Type );
+
+ virtual ~SCA_MouseSensor();
+ virtual CValue* GetReplica();
+ virtual bool Evaluate(CValue* event);
+
+ virtual bool IsPositiveTrigger();
+ short int GetModeKey();
+ SCA_IInputDevice::KX_EnumInputs GetHotKey();
+ void setX(short x);
+ void setY(short y);
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ /* read x-coordinate */
+ KX_PYMETHOD_DOC(SCA_MouseSensor,GetXPosition);
+ /* read y-coordinate */
+ KX_PYMETHOD_DOC(SCA_MouseSensor,GetYPosition);
+
+};
+
+#endif //__KX_MOUSESENSOR
+
diff --git a/source/gameengine/GameLogic/SCA_ORController.cpp b/source/gameengine/GameLogic/SCA_ORController.cpp
new file mode 100644
index 00000000000..29f62b4e6a7
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ORController.cpp
@@ -0,0 +1,139 @@
+/**
+ * 'Or' together all inputs
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_ORController.h"
+#include "SCA_ISensor.h"
+#include "SCA_LogicManager.h"
+#include "BoolValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+SCA_ORController::SCA_ORController(SCA_IObject* gameobj,
+ PyTypeObject* T)
+ :SCA_IController(gameobj, T)
+{
+}
+
+
+
+SCA_ORController::~SCA_ORController()
+{
+}
+
+
+
+CValue* SCA_ORController::GetReplica()
+{
+ CValue* replica = new SCA_ORController(*this);
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+void SCA_ORController::Trigger(SCA_LogicManager* logicmgr)
+{
+
+ bool sensorresult = false;
+ SCA_ISensor* sensor;
+
+ vector<SCA_ISensor*>::const_iterator is=m_linkedsensors.begin();
+ while ( (!sensorresult) && (!(is==m_linkedsensors.end())) )
+ {
+ sensor = *is;
+ if (sensor->IsPositiveTrigger()) sensorresult = true;
+ is++;
+ }
+
+ CValue* newevent = new CBoolValue(sensorresult);
+
+ for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin();
+ !(i==m_linkedactuators.end());i++)
+ {
+ SCA_IActuator* actua = *i;//m_linkedactuators.at(i);
+ logicmgr->AddActiveActuator(actua,newevent);
+ }
+
+
+ newevent->Release();
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject SCA_ORController::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_ORController",
+ sizeof(SCA_ORController),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_ORController::Parents[] = {
+ &SCA_ORController::Type,
+ &SCA_IController::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef SCA_ORController::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* SCA_ORController::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IController);
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_ORController.h b/source/gameengine/GameLogic/SCA_ORController.h
new file mode 100644
index 00000000000..d8b844d9063
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ORController.h
@@ -0,0 +1,59 @@
+/**
+ * SCA_ORController.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 __KX_ORCONTROLLER
+#define __KX_ORCONTROLLER
+
+#include "SCA_IController.h"
+
+class SCA_ORController : public SCA_IController
+{
+ Py_Header;
+ //virtual void Trigger(class SCA_LogicManager* logicmgr);
+public:
+ SCA_ORController(SCA_IObject* gameobj, PyTypeObject* T=&Type);
+
+ virtual ~SCA_ORController();
+ virtual CValue* GetReplica();
+ virtual void Trigger(SCA_LogicManager* logicmgr);
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+};
+
+#endif //__KX_ORCONTROLLER
+
diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp
new file mode 100644
index 00000000000..c3e2066fc65
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp
@@ -0,0 +1,288 @@
+/**
+ * Assign, change, copy properties
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_PropertyActuator.h"
+#include "InputParser.h"
+#include "Operator2Expr.h"
+#include "ConstExpr.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+SCA_PropertyActuator::SCA_PropertyActuator(SCA_IObject* gameobj,CValue* sourceObj,const STR_String& propname,const STR_String& expr,int acttype,PyTypeObject* T )
+ : SCA_IActuator(gameobj,T),
+ m_type(acttype),
+ m_propname(propname),
+ m_exprtxt(expr),
+ m_sourceObj(sourceObj)
+{
+}
+
+SCA_PropertyActuator::~SCA_PropertyActuator()
+{
+}
+
+bool SCA_PropertyActuator::Update()
+{
+ bool result = false;
+
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+
+ if (bNegativeEvent)
+ return false; // do nothing on negative events
+
+
+ CValue* propowner = GetParent();
+ CParser parser;
+ parser.SetContext( propowner->AddRef());
+
+ CExpression* userexpr = parser.ProcessText(m_exprtxt);
+ if (userexpr)
+ {
+
+
+ switch (m_type)
+ {
+
+ case KX_ACT_PROP_ASSIGN:
+ {
+
+ CValue* newval = userexpr->Calculate();
+ CValue* oldprop = propowner->GetProperty(m_propname);
+ if (oldprop)
+ {
+ oldprop->SetValue(newval);
+ newval->Release();
+ } else
+ {
+ propowner->SetProperty(m_propname,newval);
+ }
+
+ break;
+ }
+ case KX_ACT_PROP_ADD:
+ {
+ CValue* oldprop = propowner->GetProperty(m_propname);
+ if (oldprop)
+ {
+ // int waarde = (int)oldprop->GetNumber(); /*unused*/
+ CExpression* expr = new COperator2Expr(VALUE_ADD_OPERATOR,new CConstExpr(oldprop->AddRef()),
+ userexpr->AddRef());
+
+ CValue* newprop = expr->Calculate();
+ oldprop->SetValue(newprop);
+ newprop->Release();
+ expr->Release();
+
+ }
+
+ break;
+ }
+ case KX_ACT_PROP_COPY:
+ {
+ if (m_sourceObj)
+ {
+ CValue* copyprop = m_sourceObj->GetProperty(m_exprtxt);
+ if (copyprop)
+ {
+ GetParent()->SetProperty(
+ m_propname,
+ copyprop->GetReplica());
+
+ }
+ }
+ break;
+ }
+ default:
+ {
+
+ }
+ }
+
+ userexpr->Release();
+ }
+
+ return result;
+}
+
+ bool
+
+SCA_PropertyActuator::
+
+isValid(
+
+ SCA_PropertyActuator::KX_ACT_PROP_MODE mode
+
+){
+ bool res = false;
+ res = ((mode > KX_ACT_PROP_NODEF) && (mode < KX_ACT_PROP_MAX));
+ return res;
+}
+
+
+ CValue*
+
+SCA_PropertyActuator::
+
+GetReplica() {
+
+ SCA_PropertyActuator* replica = new SCA_PropertyActuator(*this);
+
+ replica->ProcessReplica();
+
+ // this will copy properties and so on...
+
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+
+};
+
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject SCA_PropertyActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_PropertyActuator",
+ sizeof(SCA_PropertyActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_PropertyActuator::Parents[] = {
+ &SCA_PropertyActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef SCA_PropertyActuator::Methods[] = {
+ {"setProperty", (PyCFunction) SCA_PropertyActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
+ {"getProperty", (PyCFunction) SCA_PropertyActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
+ {"setValue", (PyCFunction) SCA_PropertyActuator::sPySetValue, METH_VARARGS, SetValue_doc},
+ {"getValue", (PyCFunction) SCA_PropertyActuator::sPyGetValue, METH_VARARGS, GetValue_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* SCA_PropertyActuator::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IActuator);
+}
+
+/* 1. setProperty */
+char SCA_PropertyActuator::SetProperty_doc[] =
+"setProperty(name)\n"
+"\t- name: string\n"
+"\tSet the property on which to operate. If there is no property\n"
+"\tof this name, the call is ignored.\n";
+PyObject* SCA_PropertyActuator::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ /* Check whether the name exists first ! */
+ char *nameArg;
+ if (!PyArg_ParseTuple(args, "s", &nameArg)) {
+ return NULL;
+ }
+
+ CValue* prop = GetParent()->FindIdentifier(nameArg);
+
+ if (prop) {
+ m_propname = nameArg;
+ } else {
+ ; /* not found ... */
+ }
+
+ Py_Return;
+}
+
+/* 2. getProperty */
+char SCA_PropertyActuator::GetProperty_doc[] =
+"getProperty(name)\n"
+"\tReturn the property on which the actuator operates.\n";
+PyObject* SCA_PropertyActuator::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyString_FromString(m_propname);
+}
+
+/* 3. setValue */
+char SCA_PropertyActuator::SetValue_doc[] =
+"setValue(value)\n"
+"\t- value: string\n"
+"\tSet the value with which the actuator operates. If the value\n"
+"\tis not compatible with the type of the property, the subsequent\n"
+"\t action is ignored.\n";
+PyObject* SCA_PropertyActuator::PySetValue(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ char *valArg;
+ if(!PyArg_ParseTuple(args, "s", &valArg)) {
+ return NULL;
+ }
+
+ if (valArg) m_exprtxt = valArg;
+
+ Py_Return;
+}
+
+/* 4. getValue */
+char SCA_PropertyActuator::GetValue_doc[] =
+"getValue()\n"
+"\tReturns the value with which the actuator operates.\n";
+PyObject* SCA_PropertyActuator::PyGetValue(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyString_FromString(m_exprtxt);
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.h b/source/gameengine/GameLogic/SCA_PropertyActuator.h
new file mode 100644
index 00000000000..cdcda7a84e0
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_PropertyActuator.h
@@ -0,0 +1,100 @@
+/**
+ * SCA_PropertyActuator.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 __KX_PROPERTYACTUATOR
+#define __KX_PROPERTYACTUATOR
+
+#include "SCA_IActuator.h"
+
+class SCA_PropertyActuator : public SCA_IActuator
+{
+ Py_Header;
+
+ enum KX_ACT_PROP_MODE {
+ KX_ACT_PROP_NODEF = 0,
+ KX_ACT_PROP_ASSIGN,
+ KX_ACT_PROP_ADD,
+ KX_ACT_PROP_COPY,
+ KX_ACT_PROP_MAX
+ };
+
+ /**check whether this value is valid */
+ bool isValid(KX_ACT_PROP_MODE mode);
+
+ int m_type;
+ STR_String m_propname;
+ STR_String m_exprtxt;
+ CValue* m_sourceObj; // for copy property actuator
+
+public:
+
+
+
+ SCA_PropertyActuator(
+ SCA_IObject* gameobj,
+ CValue* sourceObj,
+ const STR_String& propname,
+ const STR_String& expr,
+ int acttype,
+ PyTypeObject* T=&Type
+ );
+
+
+ ~SCA_PropertyActuator();
+
+ CValue*
+ GetReplica(
+ );
+
+ virtual bool
+ Update();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ // python wrapped methods
+ KX_PYMETHOD_DOC(SCA_PropertyActuator,SetProperty);
+ KX_PYMETHOD_DOC(SCA_PropertyActuator,GetProperty);
+ KX_PYMETHOD_DOC(SCA_PropertyActuator,SetValue);
+ KX_PYMETHOD_DOC(SCA_PropertyActuator,GetValue);
+
+ /* 5. - ... setObject, getObject, setProp2, getProp2, setMode, getMode*/
+
+};
+
+#endif //__KX_PROPERTYACTUATOR_DOC
+
diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp b/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp
new file mode 100644
index 00000000000..4ac3d162229
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp
@@ -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 "SCA_ISensor.h"
+#include "SCA_PropertyEventManager.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+SCA_PropertyEventManager::SCA_PropertyEventManager(class SCA_LogicManager* logicmgr)
+ : SCA_EventManager(PROPERTY_EVENTMGR),
+ m_logicmgr(logicmgr)
+{
+}
+
+
+
+SCA_PropertyEventManager::~SCA_PropertyEventManager()
+{
+
+}
+
+
+
+void SCA_PropertyEventManager::RegisterSensor(SCA_ISensor* sensor)
+{
+ m_sensors.push_back(sensor);
+}
+
+
+
+void SCA_PropertyEventManager::NextFrame()
+{
+ // check for changed properties
+ for (vector<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++)
+ {
+ (*it)->Activate(m_logicmgr,NULL);
+ }
+}
diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.h b/source/gameengine/GameLogic/SCA_PropertyEventManager.h
new file mode 100644
index 00000000000..664beb68695
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_PropertyEventManager.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 __KX_PROPERTYEVENTMANAGER
+#define __KX_PROPERTYEVENTMANAGER
+
+#include "SCA_EventManager.h"
+
+#include <vector>
+
+using namespace std;
+
+class SCA_PropertyEventManager : public SCA_EventManager
+{
+ class SCA_LogicManager* m_logicmgr;
+
+public:
+ SCA_PropertyEventManager(class SCA_LogicManager* logicmgr);
+ virtual ~SCA_PropertyEventManager();
+ virtual void NextFrame();
+ virtual void RegisterSensor(SCA_ISensor* sensor);
+ //SCA_LogicManager* GetLogicManager() { return m_logicmgr;}
+};
+
+#endif //__KX_PROPERTYEVENTMANAGER
+
diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
new file mode 100644
index 00000000000..09332b870c9
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
@@ -0,0 +1,433 @@
+/**
+ * Property sensor
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 <iostream>
+#include "SCA_PropertySensor.h"
+#include "Operator2Expr.h"
+#include "ConstExpr.h"
+#include "InputParser.h"
+#include "StringValue.h"
+#include "SCA_EventManager.h"
+#include "SCA_LogicManager.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ const STR_String& propname,
+ const STR_String& propval,
+ const STR_String& propmaxval,
+ KX_PROPSENSOR_TYPE checktype,
+ PyTypeObject* T )
+ : SCA_ISensor(gameobj,eventmgr,T),
+ m_checktype(checktype),
+ m_checkpropval(propval),
+ m_checkpropmaxval(propmaxval),
+ m_checkpropname(propname),
+ m_lastresult(false),
+ m_range_expr(NULL)
+{
+ m_recentresult=false;
+ //CParser pars;
+ //pars.SetContext(this->AddRef());
+ //CValue* resultval = m_rightexpr->Calculate();
+
+ CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
+ if (orgprop)
+ {
+ m_previoustext = orgprop->GetText();
+ orgprop->Release();
+ }
+
+ if (m_checktype==KX_PROPSENSOR_INTERVAL)
+ {
+ PrecalculateRangeExpression();
+ }
+
+}
+
+void SCA_PropertySensor::PrecalculateRangeExpression()
+{
+ CParser pars;
+ pars.SetContext(this->AddRef());
+ STR_String checkstr = "(" + m_checkpropval + " <= "
+ + m_checkpropname + ") && ( "
+ + m_checkpropname + " <= "
+ + m_checkpropmaxval;
+
+ m_range_expr = pars.ProcessText(checkstr);
+}
+
+
+
+CValue* SCA_PropertySensor::GetReplica()
+{
+ SCA_PropertySensor* replica = new SCA_PropertySensor(*this);
+ // m_range_expr must be recalculated on replica!
+ CValue::AddDataToReplica(replica);
+
+ replica->m_range_expr = NULL;
+ if (replica->m_checktype==KX_PROPSENSOR_INTERVAL)
+ {
+ replica->PrecalculateRangeExpression();
+ }
+
+
+ return replica;
+}
+
+
+
+bool SCA_PropertySensor::IsPositiveTrigger()
+{
+ bool result = m_recentresult;//CheckPropertyCondition();
+ if (m_invert)
+ result = !result;
+
+ return result;
+}
+
+
+
+SCA_PropertySensor::~SCA_PropertySensor()
+{
+ //if (m_rightexpr)
+ // m_rightexpr->Release();
+
+ if (m_range_expr)
+ {
+ m_range_expr->Release();
+ m_range_expr=NULL;
+ }
+
+}
+
+
+
+bool SCA_PropertySensor::Evaluate(CValue* event)
+{
+ bool result = CheckPropertyCondition();
+
+ if (m_lastresult!=result)
+ {
+ m_lastresult = result;
+ return true;
+ }
+
+ return false;
+}
+
+
+bool SCA_PropertySensor::CheckPropertyCondition()
+{
+
+ m_recentresult=false;
+ bool result=false;
+ bool reverse = false;
+ switch (m_checktype)
+ {
+ case KX_PROPSENSOR_NOTEQUAL:
+ reverse = true;
+ case KX_PROPSENSOR_EQUAL:
+ {
+ CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
+ if (orgprop)
+ {
+ STR_String testprop = orgprop->GetText();
+ // Force strings to upper case, to avoid confusion in
+ // bool tests. It's stupid the prop's identity is lost
+ // on the way here...
+ if ((testprop == "TRUE") || (testprop == "FALSE")) {
+ STR_String checkprop = m_checkpropval;
+ checkprop.Upper();
+ result = (testprop == checkprop);
+ } else {
+ result = (orgprop->GetText() == m_checkpropval);
+ }
+ orgprop->Release();
+
+ }
+
+ if (reverse)
+ result = !result;
+ break;
+
+ }
+
+ case KX_PROPSENSOR_EXPRESSION:
+ {
+ /*
+ if (m_rightexpr)
+ {
+ CValue* resultval = m_rightexpr->Calculate();
+ if (resultval->IsError())
+ {
+ int i=0;
+ STR_String errortest = resultval->GetText();
+ printf(errortest);
+
+ } else
+ {
+ result = resultval->GetNumber() != 0;
+ }
+ }
+ */
+ break;
+ }
+ case KX_PROPSENSOR_INTERVAL:
+ {
+ //CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
+ //if (orgprop)
+ //{
+ if (m_range_expr)
+ {
+ CValue* vallie = m_range_expr->Calculate();
+ if (vallie)
+ {
+ STR_String errtext = vallie->GetText();
+ if (errtext == "TRUE")
+ {
+ result = true;
+ } else
+ {
+ if (vallie->IsError())
+ {
+ //printf (errtext.ReadPtr());
+ }
+ }
+
+ vallie->Release();
+ }
+ }
+
+
+ //}
+
+ //cout << " \nSens:Prop:interval!"; /* need implementation here!!! */
+
+ break;
+ }
+ case KX_PROPSENSOR_CHANGED:
+ {
+ CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
+
+ if (orgprop)
+ {
+ if (m_previoustext != orgprop->GetText())
+ {
+ m_previoustext = orgprop->GetText();
+ result = true;
+ }
+ orgprop->Release();
+ }
+
+ //cout << " \nSens:Prop:changed!"; /* need implementation here!!! */
+ break;
+ }
+ default:
+ ; /* error */
+ }
+
+ //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED
+ //see Game Engine bugtracker [ #3809 ]
+ if (m_checktype != KX_PROPSENSOR_CHANGED)
+ {
+ m_recentresult=result;
+ } else
+ {
+ m_recentresult=result;//true;
+ }
+ return result;
+}
+
+CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername)
+{
+ return GetParent()->FindIdentifier(identifiername);
+}
+
+bool SCA_PropertySensor::validValueForProperty(char *val, STR_String &prop)
+{
+ bool result = true;
+ /* There is no type checking at this moment, unfortunately... */
+ return result;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject SCA_PropertySensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_PropertySensor",
+ sizeof(SCA_PropertySensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_PropertySensor::Parents[] = {
+ &SCA_PropertySensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef SCA_PropertySensor::Methods[] = {
+ {"getType", (PyCFunction) SCA_PropertySensor::sPyGetType, METH_VARARGS, GetType_doc},
+ {"setType", (PyCFunction) SCA_PropertySensor::sPySetType, METH_VARARGS, SetType_doc},
+ {"getProperty", (PyCFunction) SCA_PropertySensor::sPyGetProperty, METH_VARARGS, GetProperty_doc},
+ {"setProperty", (PyCFunction) SCA_PropertySensor::sPySetProperty, METH_VARARGS, SetProperty_doc},
+ {"getValue", (PyCFunction) SCA_PropertySensor::sPyGetValue, METH_VARARGS, GetValue_doc},
+ {"setValue", (PyCFunction) SCA_PropertySensor::sPySetValue, METH_VARARGS, SetValue_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* SCA_PropertySensor::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_ISensor); /* implicit return! */
+}
+
+/* 1. getType */
+char SCA_PropertySensor::GetType_doc[] =
+"getType()\n"
+"\tReturns the type of check this sensor performs.\n";
+PyObject* SCA_PropertySensor::PyGetType(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyInt_FromLong(m_checktype);
+}
+
+/* 2. setType */
+char SCA_PropertySensor::SetType_doc[] =
+"setType(type)\n"
+"\t- type: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL,\n"
+"\t KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED,\n"
+"\t or KX_PROPSENSOR_EXPRESSION.\n"
+"\tSet the type of check to perform.\n";
+PyObject* SCA_PropertySensor::PySetType(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int typeArg;
+
+ if (!PyArg_ParseTuple(args, "i", &typeArg)) {
+ return NULL;
+ }
+
+ if ( (typeArg > KX_PROPSENSOR_NODEF)
+ && (typeArg < KX_PROPSENSOR_MAX) ) {
+ m_checktype = typeArg;
+ }
+
+ Py_Return;
+}
+
+/* 3. getProperty */
+char SCA_PropertySensor::GetProperty_doc[] =
+"getProperty()\n"
+"\tReturn the property with which the sensor operates.\n";
+PyObject* SCA_PropertySensor::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyString_FromString(m_checkpropname);
+}
+
+/* 4. setProperty */
+char SCA_PropertySensor::SetProperty_doc[] =
+"setProperty(name)\n"
+"\t- name: string\n"
+"\tSets the property with which to operate. If there is no property\n"
+"\tof this name, the call is ignored.\n";
+PyObject* SCA_PropertySensor::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ /* We should query whether the name exists. Or should we create a prop */
+ /* on the fly? */
+ char *propNameArg = NULL;
+
+ if (!PyArg_ParseTuple(args, "s", &propNameArg)) {
+ return NULL;
+ }
+
+ if (FindIdentifier(STR_String(propNameArg))) {
+ m_checkpropname = propNameArg;
+ } else {
+ ; /* error: bad property name */
+ }
+
+ Py_Return;
+}
+
+/* 5. getValue */
+char SCA_PropertySensor::GetValue_doc[] =
+"getValue()\n"
+"\tReturns the value with which the sensor operates.\n";
+PyObject* SCA_PropertySensor::PyGetValue(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyString_FromString(m_checkpropval);
+}
+
+/* 6. setValue */
+char SCA_PropertySensor::SetValue_doc[] =
+"setValue(value)\n"
+"\t- value: string\n"
+"\tSet the value with which the sensor operates. If the value\n"
+"\tis not compatible with the type of the property, the subsequent\n"
+"\t action is ignored.\n";
+PyObject* SCA_PropertySensor::PySetValue(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ /* Here, we need to check whether the value is 'valid' for this property.*/
+ /* We know that the property exists, or is NULL. */
+ char *propValArg = NULL;
+
+ if(!PyArg_ParseTuple(args, "s", &propValArg)) {
+ return NULL;
+ }
+
+ if (validValueForProperty(propValArg, m_checkpropname)) {
+ m_checkpropval = propValArg;
+ }
+
+ Py_Return;
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.h b/source/gameengine/GameLogic/SCA_PropertySensor.h
new file mode 100644
index 00000000000..0ebcacdb21a
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.h
@@ -0,0 +1,111 @@
+/**
+ * Property sensor
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_PROPERTYSENSOR
+#define __KX_PROPERTYSENSOR
+
+#include "SCA_ISensor.h"
+
+class SCA_PropertySensor : public SCA_ISensor
+{
+ Py_Header;
+ //class CExpression* m_rightexpr;
+ int m_checktype;
+ STR_String m_checkpropval;
+ STR_String m_checkpropmaxval;
+ STR_String m_checkpropname;
+ STR_String m_previoustext;
+ bool m_lastresult;
+ bool m_recentresult;
+ CExpression* m_range_expr;
+
+ /**
+ * Test whether this is a sensible value (type check)
+ */
+ bool validValueForProperty(char *val, STR_String &prop);
+ protected:
+
+public:
+ enum KX_PROPSENSOR_TYPE {
+ KX_PROPSENSOR_NODEF = 0,
+ KX_PROPSENSOR_EQUAL,
+ KX_PROPSENSOR_NOTEQUAL,
+ KX_PROPSENSOR_INTERVAL,
+ KX_PROPSENSOR_CHANGED,
+ KX_PROPSENSOR_EXPRESSION,
+ KX_PROPSENSOR_MAX
+ };
+
+ const STR_String S_KX_PROPSENSOR_EQ_STRING;
+
+ SCA_PropertySensor(class SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ const STR_String& propname,
+ const STR_String& propval,
+ const STR_String& propmaxval,
+ KX_PROPSENSOR_TYPE checktype,
+ PyTypeObject* T=&Type );
+
+ virtual ~SCA_PropertySensor();
+ virtual CValue* GetReplica();
+ void PrecalculateRangeExpression();
+ bool CheckPropertyCondition();
+
+ virtual bool Evaluate(CValue* event);
+ virtual bool IsPositiveTrigger();
+ virtual CValue* FindIdentifier(const STR_String& identifiername);
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ /* 1. getType */
+ KX_PYMETHOD_DOC(SCA_PropertySensor,GetType);
+ /* 2. setType */
+ KX_PYMETHOD_DOC(SCA_PropertySensor,SetType);
+ /* 3. setProperty */
+ KX_PYMETHOD_DOC(SCA_PropertySensor,SetProperty);
+ /* 4. getProperty */
+ KX_PYMETHOD_DOC(SCA_PropertySensor,GetProperty);
+ /* 5. getValue */
+ KX_PYMETHOD_DOC(SCA_PropertySensor,GetValue);
+ /* 6. setValue */
+ KX_PYMETHOD_DOC(SCA_PropertySensor,SetValue);
+
+};
+
+#endif
+
diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp
new file mode 100644
index 00000000000..c44971d7028
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_PythonController.cpp
@@ -0,0 +1,448 @@
+/**
+ * Execute Python scripts
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_PythonController.h"
+#include "SCA_LogicManager.h"
+#include "SCA_ISensor.h"
+#include "SCA_IActuator.h"
+#include "compile.h"
+#include "eval.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// initialize static member variables
+SCA_PythonController* SCA_PythonController::m_sCurrentController = NULL;
+
+
+SCA_PythonController::SCA_PythonController(SCA_IObject* gameobj,
+ PyTypeObject* T)
+ : SCA_IController(gameobj, T),
+ m_bytecode(NULL),
+ m_bModified(true),
+ m_pythondictionary(NULL)
+{
+}
+
+/*
+//debugging
+CValue* SCA_PythonController::AddRef()
+{
+ //printf("AddRef refcount = %i\n",GetRefCount());
+ return CValue::AddRef();
+}
+int SCA_PythonController::Release()
+{
+ //printf("Release refcount = %i\n",GetRefCount());
+ return CValue::Release();
+}
+*/
+
+
+
+SCA_PythonController::~SCA_PythonController()
+{
+ if (m_bytecode)
+ {
+ //
+ //printf("released python byte script\n");
+ Py_DECREF(m_bytecode);
+ }
+
+ if (m_pythondictionary)
+ {
+ // break any circular references in the dictionary
+ PyDict_Clear(m_pythondictionary);
+ Py_DECREF(m_pythondictionary);
+ }
+}
+
+
+
+CValue* SCA_PythonController::GetReplica()
+{
+ SCA_PythonController* replica = new SCA_PythonController(*this);
+ // Copy the compiled bytecode if possible.
+ Py_XINCREF(replica->m_bytecode);
+ replica->m_bModified = replica->m_bytecode == NULL;
+
+ // The replica->m_pythondictionary is stolen - replace with a copy.
+ if (m_pythondictionary)
+ replica->m_pythondictionary = PyDict_Copy(m_pythondictionary);
+
+ /*
+ // The other option is to incref the replica->m_pythondictionary -
+ // the replica objects can then share data.
+ if (m_pythondictionary)
+ Py_INCREF(replica->m_pythondictionary);
+ */
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+void SCA_PythonController::SetScriptText(const STR_String& text)
+{
+ m_scriptText = "import GameLogic\n" + text;
+ m_bModified = true;
+}
+
+
+
+void SCA_PythonController::SetScriptName(const STR_String& name)
+{
+ m_scriptName = name;
+}
+
+
+
+void SCA_PythonController::SetDictionary(PyObject* pythondictionary)
+{
+ if (m_pythondictionary)
+ {
+ PyDict_Clear(m_pythondictionary);
+ Py_DECREF(m_pythondictionary);
+ }
+ m_pythondictionary = PyDict_Copy(pythondictionary); /* new reference */
+}
+
+#if 0
+static char* sPyGetCurrentController__doc__;
+#endif
+
+
+PyObject* SCA_PythonController::sPyGetCurrentController(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ m_sCurrentController->AddRef();
+ return m_sCurrentController;
+}
+
+#if 0
+static char* sPyAddActiveActuator__doc__;
+#endif
+
+PyObject* SCA_PythonController::sPyAddActiveActuator(
+
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ PyObject* ob1;
+ int activate;
+ if (!PyArg_ParseTuple(args, "Oi", &ob1,&activate))
+ return NULL;
+
+ // for safety, todo: only allow for registered actuators (pointertable)
+ // we don't want to crash gameengine/blender by python scripts
+ std::vector<SCA_IActuator*> lacts = m_sCurrentController->GetLinkedActuators();
+
+ std::vector<SCA_IActuator*>::iterator it;
+ bool found = false;
+ CValue* act = (CValue*)ob1;
+
+ for(it = lacts.begin(); it!= lacts.end(); it++) {
+ if( static_cast<SCA_IActuator*>(act) == (*it) ) {
+ found=true;
+ break;
+ }
+ }
+ if(found){
+ CValue* boolval = new CBoolValue(activate!=0);
+ m_sCurrentLogicManager->AddActiveActuator((SCA_IActuator*)act,boolval);
+ boolval->Release();
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+char* SCA_PythonController::sPyGetCurrentController__doc__ = "getCurrentController()";
+char* SCA_PythonController::sPyAddActiveActuator__doc__= "addActiveActuator(actuator,bool)";
+char SCA_PythonController::GetActuators_doc[] = "getActuator";
+
+PyTypeObject SCA_PythonController::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_PythonController",
+ sizeof(SCA_PythonController),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_PythonController::Parents[] = {
+ &SCA_PythonController::Type,
+ &SCA_IController::Type,
+ &CValue::Type,
+ NULL
+};
+PyMethodDef SCA_PythonController::Methods[] = {
+ {"getActuators", (PyCFunction) SCA_PythonController::sPyGetActuators,
+ METH_VARARGS, SCA_PythonController::GetActuators_doc},
+ {"getActuator", (PyCFunction) SCA_PythonController::sPyGetActuator,
+ METH_VARARGS, SCA_PythonController::GetActuator_doc},
+ {"getSensors", (PyCFunction) SCA_PythonController::sPyGetSensors,
+ METH_VARARGS, SCA_PythonController::GetSensors_doc},
+ {"getSensor", (PyCFunction) SCA_PythonController::sPyGetSensor,
+ METH_VARARGS, SCA_PythonController::GetSensor_doc},
+ {"getScript", (PyCFunction) SCA_PythonController::sPyGetScript, METH_VARARGS},
+ {"setScript", (PyCFunction) SCA_PythonController::sPySetScript, METH_VARARGS},
+ {NULL,NULL} //Sentinel
+};
+
+
+void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr)
+{
+ m_sCurrentController = this;
+ m_sCurrentLogicManager = logicmgr;
+
+ if (m_bModified)
+ {
+ // if a script already exists, decref it before replace the pointer to a new script
+ if (m_bytecode)
+ {
+ Py_DECREF(m_bytecode);
+ m_bytecode=NULL;
+ }
+ // recompile the scripttext into bytecode
+ m_bytecode = Py_CompileString(m_scriptText.Ptr(), m_scriptName.Ptr(), Py_file_input);
+ if (!m_bytecode)
+ {
+ // didn't compile, so instead of compile, complain
+ // something is wrong, tell the user what went wrong
+ printf("PYTHON SCRIPT ERROR:\n");
+ //PyRun_SimpleString(m_scriptText.Ptr());
+ PyErr_Print();
+ return;
+ }
+ m_bModified=false;
+ }
+
+ /*
+ * This part here with excdict is a temporary patch
+ * to avoid python/gameengine crashes when python
+ * inadvertently holds references to game objects
+ * in global variables.
+ *
+ * The idea is always make a fresh dictionary, and
+ * destroy it right after it is used to make sure
+ * python won't hold any gameobject references.
+ *
+ * Note that the PyDict_Clear _is_ necessary before
+ * the Py_DECREF() because it is possible for the
+ * variables inside the dictionary to hold references
+ * to the dictionary (ie. generate a cycle), so we
+ * break it by hand, then DECREF (which in this case
+ * should always ensure excdict is cleared).
+ */
+/* PyObject *excdict= myPyDict_Copy(m_pythondictionary);
+ struct _object* resultobj = PyEval_EvalCode((PyCodeObject*)m_bytecode,
+ excdict,
+ excdict
+ );
+ PyDict_Clear(excdict);
+ Py_DECREF(excdict);*/
+
+
+#if 1
+ PyObject *excdict= PyDict_Copy(m_pythondictionary);
+ PyObject* resultobj = PyEval_EvalCode((PyCodeObject*)m_bytecode,
+ excdict,
+ excdict
+ );
+ PyDict_Clear(excdict);
+ Py_DECREF(excdict);
+#else
+
+ PyObject* resultobj = PyEval_EvalCode((PyCodeObject*)m_bytecode,
+ m_pythondictionary,
+ m_pythondictionary
+ );
+
+#endif
+
+ if (resultobj)
+ {
+ Py_DECREF(resultobj);
+ } else
+ {
+ // something is wrong, tell the user what went wrong
+ printf("PYTHON SCRIPT ERROR:\n");
+ PyErr_Print();
+ //PyRun_SimpleString(m_scriptText.Ptr());
+ }
+
+ m_sCurrentController = NULL;
+}
+
+
+
+PyObject* SCA_PythonController::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_IController);
+}
+
+
+
+PyObject* SCA_PythonController::PyGetActuators(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject* resultlist = PyList_New(m_linkedactuators.size());
+ for (unsigned int index=0;index<m_linkedactuators.size();index++)
+ {
+ PyList_SetItem(resultlist,index,m_linkedactuators[index]->AddRef());
+ }
+
+ return resultlist;
+}
+
+char SCA_PythonController::GetSensor_doc[] =
+"GetSensor (char sensorname) return linked sensor that is named [sensorname]\n";
+PyObject*
+SCA_PythonController::PyGetSensor(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ char *scriptArg;
+
+ if (!PyArg_ParseTuple(args, "s", &scriptArg)) {
+ return NULL;
+ }
+
+ for (unsigned int index=0;index<m_linkedsensors.size();index++)
+ {
+ SCA_ISensor* sensor = m_linkedsensors[index];
+ STR_String realname = sensor->GetName();
+ if (realname == scriptArg)
+ {
+ return sensor->AddRef();
+ }
+ }
+
+ PyErr_SetString(PyExc_AttributeError, "Unable to find requested sensor");
+ return NULL;
+}
+
+
+
+char SCA_PythonController::GetActuator_doc[] =
+"GetActuator (char sensorname) return linked actuator that is named [actuatorname]\n";
+PyObject*
+SCA_PythonController::PyGetActuator(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ char *scriptArg;
+
+ if (!PyArg_ParseTuple(args, "s", &scriptArg)) {
+ return NULL;
+ }
+
+ for (unsigned int index=0;index<m_linkedactuators.size();index++)
+ {
+ SCA_IActuator* actua = m_linkedactuators[index];
+ STR_String realname = actua->GetName();
+ if (realname == scriptArg)
+ {
+ return actua->AddRef();
+ }
+ }
+
+ PyErr_SetString(PyExc_AttributeError, "Unable to find requested actuator");
+ return NULL;
+}
+
+
+char SCA_PythonController::GetSensors_doc[] = "getSensors returns a list of all attached sensors";
+PyObject*
+SCA_PythonController::PyGetSensors(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject* resultlist = PyList_New(m_linkedsensors.size());
+ for (unsigned int index=0;index<m_linkedsensors.size();index++)
+ {
+ PyList_SetItem(resultlist,index,m_linkedsensors[index]->AddRef());
+ }
+
+ return resultlist;
+}
+
+/* 1. getScript */
+PyObject* SCA_PythonController::PyGetScript(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyString_FromString(m_scriptText);
+}
+
+/* 2. setScript */
+PyObject* SCA_PythonController::PySetScript(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ char *scriptArg;
+ if (!PyArg_ParseTuple(args, "s", &scriptArg)) {
+ return NULL;
+ }
+
+ /* set scripttext sets m_bModified to true,
+ so next time the script is needed, a reparse into byte code is done */
+
+ this->SetScriptText(scriptArg);
+
+ Py_Return;
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_PythonController.h b/source/gameengine/GameLogic/SCA_PythonController.h
new file mode 100644
index 00000000000..da2cd4b0bcd
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_PythonController.h
@@ -0,0 +1,92 @@
+/**
+ * Execute Python scripts
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 KX_PYTHONCONTROLLER_H
+#define KX_PYTHONCONTROLLER_H
+
+#include "SCA_IController.h"
+#include "SCA_LogicManager.h"
+#include "BoolValue.h"
+
+class SCA_IObject;
+class SCA_PythonController : public SCA_IController
+{
+ Py_Header;
+ struct _object * m_bytecode;
+ bool m_bModified;
+
+ protected:
+ STR_String m_scriptText;
+ STR_String m_scriptName;
+ PyObject* m_pythondictionary;
+
+ public:
+ static SCA_PythonController* m_sCurrentController; // protected !!!
+
+ //for debugging
+ //virtual CValue* AddRef();
+ //virtual int Release(); // Release a reference to this value (when reference count reaches 0, the value is removed from the heap)
+
+ SCA_PythonController(SCA_IObject* gameobj,PyTypeObject* T = &Type);
+ virtual ~SCA_PythonController();
+
+ virtual CValue* GetReplica();
+ virtual void Trigger(class SCA_LogicManager* logicmgr);
+
+ void SetScriptText(const STR_String& text);
+ void SetScriptName(const STR_String& name);
+ void SetDictionary(PyObject* pythondictionary);
+
+ static char* sPyGetCurrentController__doc__;
+ static PyObject* sPyGetCurrentController(PyObject* self,
+ PyObject* args,
+ PyObject* kwds);
+ static char* sPyAddActiveActuator__doc__;
+ static PyObject* sPyAddActiveActuator(PyObject* self,
+ PyObject* args,
+ PyObject* kwds);
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ KX_PYMETHOD_DOC(SCA_PythonController,GetSensors);
+ KX_PYMETHOD_DOC(SCA_PythonController,GetSensor);
+ KX_PYMETHOD_DOC(SCA_PythonController,GetActuator);
+ KX_PYMETHOD_DOC(SCA_PythonController,GetActuators);
+ KX_PYMETHOD(SCA_PythonController,SetScript);
+ KX_PYMETHOD(SCA_PythonController,GetScript);
+
+
+};
+
+#endif //KX_PYTHONCONTROLLER_H
+
diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.cpp b/source/gameengine/GameLogic/SCA_RandomActuator.cpp
new file mode 100644
index 00000000000..474ad08eee3
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_RandomActuator.cpp
@@ -0,0 +1,642 @@
+/**
+ * Set random/camera 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 *****
+ */
+
+#include "BoolValue.h"
+#include "IntValue.h"
+#include "FloatValue.h"
+#include "SCA_IActuator.h"
+#include "SCA_RandomActuator.h"
+#include "math.h"
+#include "MT_Transform.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+SCA_RandomActuator::SCA_RandomActuator(SCA_IObject *gameobj,
+ long seed,
+ SCA_RandomActuator::KX_RANDOMACT_MODE mode,
+ float para1,
+ float para2,
+ const STR_String &propName,
+ PyTypeObject* T)
+ : SCA_IActuator(gameobj, T),
+ m_propname(propName),
+ m_parameter1(para1),
+ m_parameter2(para2),
+ m_distribution(mode)
+{
+ m_base = new SCA_RandomNumberGenerator(seed);
+ m_counter = 0;
+ enforceConstraints();
+}
+
+
+
+SCA_RandomActuator::~SCA_RandomActuator()
+{
+ /* intentionally empty */
+}
+
+
+
+CValue* SCA_RandomActuator::GetReplica()
+{
+ SCA_RandomActuator* replica = new SCA_RandomActuator(*this);
+ replica->ProcessReplica();
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+bool SCA_RandomActuator::Update()
+{
+ //bool result = false; /*unused*/
+ bool bNegativeEvent = IsNegativeEvent();
+
+ RemoveAllEvents();
+
+
+ CValue *tmpval = NULL;
+
+ if (bNegativeEvent)
+ return false; // do nothing on negative events
+
+ switch (m_distribution) {
+ case KX_RANDOMACT_BOOL_CONST: {
+ /* un petit peu filthy */
+ bool res = !(m_parameter1 < 0.5);
+ tmpval = new CBoolValue(res);
+ }
+ break;
+ case KX_RANDOMACT_BOOL_UNIFORM: {
+ /* flip a coin */
+ bool res;
+ if (m_counter > 31) {
+ m_previous = m_base->Draw();
+ res = ((m_previous & 0x1) == 0);
+ m_counter = 1;
+ } else {
+ res = (((m_previous >> m_counter) & 0x1) == 0);
+ m_counter++;
+ }
+ tmpval = new CBoolValue(res);
+ }
+ break;
+ case KX_RANDOMACT_BOOL_BERNOUILLI: {
+ /* 'percentage' */
+ bool res;
+ res = (m_base->DrawFloat() < m_parameter1);
+ tmpval = new CBoolValue(res);
+ }
+ break;
+ case KX_RANDOMACT_INT_CONST: {
+ /* constant */
+ tmpval = new CIntValue((int) floor(m_parameter1));
+ }
+ break;
+ case KX_RANDOMACT_INT_UNIFORM: {
+ /* uniform (toss a die) */
+ int res;
+ /* The [0, 1] interval is projected onto the [min, max+1] domain, */
+ /* and then rounded. */
+ res = (int) floor( ((m_parameter2 - m_parameter1 + 1) * m_base->DrawFloat())
+ + m_parameter1);
+ tmpval = new CIntValue(res);
+ }
+ break;
+ case KX_RANDOMACT_INT_POISSON: {
+ /* poisson (queues) */
+ /* If x_1, x_2, ... is a sequence of random numbers with uniform */
+ /* distribution between zero and one, k is the first integer for */
+ /* which the product x_1*x_2*...*x_k < exp(-\lamba). */
+ float a = 0.0, b = 0.0;
+ int res = 0;
+ /* The - sign is important here! The number to test for, a, must be */
+ /* between 0 and 1. */
+ a = exp(-m_parameter1);
+ /* a quickly reaches 0.... so we guard explicitly for that. */
+ if (a < FLT_MIN) a = FLT_MIN;
+ b = m_base->DrawFloat();
+ while (b >= a) {
+ b = b * m_base->DrawFloat();
+ res++;
+ };
+ tmpval = new CIntValue(res);
+ }
+ break;
+ case KX_RANDOMACT_FLOAT_CONST: {
+ /* constant */
+ tmpval = new CFloatValue(m_parameter1);
+ }
+ break;
+ case KX_RANDOMACT_FLOAT_UNIFORM: {
+ float res = ((m_parameter2 - m_parameter1) * m_base->DrawFloat())
+ + m_parameter1;
+ tmpval = new CFloatValue(res);
+ }
+ break;
+ case KX_RANDOMACT_FLOAT_NORMAL: {
+ /* normal (big numbers): para1 = mean, para2 = std dev */
+
+ /*
+
+ 070301 - nzc - Changed the termination condition. I think I
+ made a small mistake here, but it only affects distro's where
+ the seed equals 0. In that case, the algorithm locks. Let's
+ just guard that case separately.
+
+ */
+
+ float x = 0.0, y = 0.0, s = 0.0, t = 0.0;
+ if (m_base->GetSeed() == 0) {
+ /*
+
+ 070301 - nzc
+ Just taking the mean here seems reasonable.
+
+ */
+ tmpval = new CFloatValue(m_parameter1);
+ } else {
+ /*
+
+ 070301 - nzc
+ Now, with seed != 0, we will most assuredly get some
+ sensible values. The termination condition states two
+ things:
+ 1. s >= 0 is not allowed: to prevent the distro from
+ getting a bias towards high values. This is a small
+ correction, really, and might also be left out.
+ 2. s == 0 is not allowed: to prevent a division by zero
+ when renormalising the drawn value to the desired
+ distribution shape. As a side effect, the distro will
+ never yield the exact mean.
+ I am not sure whether this is consistent, since the error
+ cause by #2 is of the same magnitude as the one
+ prevented by #1. The error introduced into the SD will be
+ improved, though. By how much? Hard to say... If you like
+ the maths, feel free to analyse. Be aware that this is
+ one of the really old standard algorithms. I think the
+ original came in Fortran, was translated to Pascal, and
+ then someone came up with the C code. My guess it that
+ this will be quite sufficient here.
+
+ */
+ do
+ {
+ x = 2.0 * m_base->DrawFloat() - 1.0;
+ y = 2.0 * m_base->DrawFloat() - 1.0;
+ s = x*x + y*y;
+ } while ( (s >= 1.0) || (s == 0.0) );
+ t = x * sqrt( (-2.0 * log(s)) / s);
+ tmpval = new CFloatValue(m_parameter1 + m_parameter2 * t);
+ }
+ }
+ break;
+ case KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: {
+ /* 1st order fall-off. I am very partial to using the half-life as */
+ /* controlling parameter. Using the 'normal' exponent is not very */
+ /* intuitive... */
+ /* tmpval = new CFloatValue( (1.0 / m_parameter1) */
+ tmpval = new CFloatValue( (m_parameter1)
+ * (-log(1.0 - m_base->DrawFloat())) );
+
+ }
+ break;
+ default:
+ {
+ /* unknown distribution... */
+ static bool randomWarning = false;
+ if (!randomWarning) {
+ randomWarning = true;
+ std::cout << "RandomActuator '" << GetName() << "' has an unknown distribution." << std::endl;
+ }
+ return false;
+ }
+ }
+
+ /* Round up: assign it */
+ CValue *prop = GetParent()->GetProperty(m_propname);
+ if (prop) {
+ prop->SetValue(tmpval);
+ }
+ tmpval->Release();
+
+ return false;
+}
+
+void SCA_RandomActuator::enforceConstraints() {
+ /* The constraints that are checked here are the ones fundamental to */
+ /* the various distributions. Limitations of the algorithms are checked */
+ /* elsewhere (or they should be... ). */
+ switch (m_distribution) {
+ case KX_RANDOMACT_BOOL_CONST:
+ case KX_RANDOMACT_BOOL_UNIFORM:
+ case KX_RANDOMACT_INT_CONST:
+ case KX_RANDOMACT_INT_UNIFORM:
+ case KX_RANDOMACT_FLOAT_UNIFORM:
+ case KX_RANDOMACT_FLOAT_CONST:
+ ; /* Nothing to be done here. We allow uniform distro's to have */
+ /* 'funny' domains, i.e. max < min. This does not give problems. */
+ break;
+ case KX_RANDOMACT_BOOL_BERNOUILLI:
+ /* clamp to [0, 1] */
+ if (m_parameter1 < 0.0) {
+ m_parameter1 = 0.0;
+ } else if (m_parameter1 > 1.0) {
+ m_parameter1 = 1.0;
+ }
+ break;
+ case KX_RANDOMACT_INT_POISSON:
+ /* non-negative */
+ if (m_parameter1 < 0.0) {
+ m_parameter1 = 0.0;
+ }
+ break;
+ case KX_RANDOMACT_FLOAT_NORMAL:
+ /* standard dev. is non-negative */
+ if (m_parameter2 < 0.0) {
+ m_parameter2 = 0.0;
+ }
+ break;
+ case KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL:
+ /* halflife must be non-negative */
+ if (m_parameter1 < 0.0) {
+ m_parameter1 = 0.0;
+ }
+ break;
+ default:
+ ; /* unknown distribution... */
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject SCA_RandomActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_RandomActuator",
+ sizeof(SCA_RandomActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_RandomActuator::Parents[] = {
+ &SCA_RandomActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef SCA_RandomActuator::Methods[] = {
+ {"setSeed", (PyCFunction) SCA_RandomActuator::sPySetSeed, METH_VARARGS, SetSeed_doc},
+ {"getSeed", (PyCFunction) SCA_RandomActuator::sPyGetSeed, METH_VARARGS, GetSeed_doc},
+ {"getPara1", (PyCFunction) SCA_RandomActuator::sPyGetPara1, METH_VARARGS, GetPara1_doc},
+ {"getPara2", (PyCFunction) SCA_RandomActuator::sPyGetPara2, METH_VARARGS, GetPara2_doc},
+ {"getDistribution", (PyCFunction) SCA_RandomActuator::sPyGetDistribution, METH_VARARGS, GetDistribution_doc},
+ {"setProperty", (PyCFunction) SCA_RandomActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
+ {"getProperty", (PyCFunction) SCA_RandomActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
+ {"setBoolConst", (PyCFunction) SCA_RandomActuator::sPySetBoolConst, METH_VARARGS, SetBoolConst_doc},
+ {"setBoolUniform", (PyCFunction) SCA_RandomActuator::sPySetBoolUniform, METH_VARARGS, SetBoolUniform_doc},
+ {"setBoolBernouilli",(PyCFunction) SCA_RandomActuator::sPySetBoolBernouilli, METH_VARARGS, SetBoolBernouilli_doc},
+ {"setIntConst", (PyCFunction) SCA_RandomActuator::sPySetIntConst, METH_VARARGS, SetIntConst_doc},
+ {"setIntUniform", (PyCFunction) SCA_RandomActuator::sPySetIntUniform, METH_VARARGS, SetIntUniform_doc},
+ {"setIntPoisson", (PyCFunction) SCA_RandomActuator::sPySetIntPoisson, METH_VARARGS, SetIntPoisson_doc},
+ {"setFloatConst", (PyCFunction) SCA_RandomActuator::sPySetFloatConst, METH_VARARGS, SetFloatConst_doc},
+ {"setFloatUniform", (PyCFunction) SCA_RandomActuator::sPySetFloatUniform, METH_VARARGS, SetFloatUniform_doc},
+ {"setFloatNormal", (PyCFunction) SCA_RandomActuator::sPySetFloatNormal, METH_VARARGS, SetFloatNormal_doc},
+ {"setFloatNegativeExponential", (PyCFunction) SCA_RandomActuator::sPySetFloatNegativeExponential, METH_VARARGS, SetFloatNegativeExponential_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* SCA_RandomActuator::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IActuator);
+}
+
+/* 1. setSeed */
+char SCA_RandomActuator::SetSeed_doc[] =
+"setSeed(seed)\n"
+"\t- seed: integer\n"
+"\tSet the initial seed of the generator. Equal seeds produce\n"
+"\tequal series. If the seed is 0, the generator will produce\n"
+"\tthe same value on every call.\n";
+PyObject* SCA_RandomActuator::PySetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
+ long seedArg;
+ if(!PyArg_ParseTuple(args, "i", &seedArg)) {
+ return NULL;
+ }
+
+ m_base->SetSeed(seedArg);
+
+ Py_Return;
+}
+/* 2. getSeed */
+char SCA_RandomActuator::GetSeed_doc[] =
+"getSeed()\n"
+"\tReturns the initial seed of the generator. Equal seeds produce\n"
+"\tequal series.\n";
+PyObject* SCA_RandomActuator::PyGetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
+ return PyInt_FromLong(m_base->GetSeed());
+}
+
+/* 4. getPara1 */
+char SCA_RandomActuator::GetPara1_doc[] =
+"getPara1()\n"
+"\tReturns the first parameter of the active distribution. Refer\n"
+"\tto the documentation of the generator types for the meaning\n"
+"\tof this value.";
+PyObject* SCA_RandomActuator::PyGetPara1(PyObject* self, PyObject* args, PyObject* kwds) {
+ return PyFloat_FromDouble(m_parameter1);
+}
+
+/* 6. getPara2 */
+char SCA_RandomActuator::GetPara2_doc[] =
+"getPara2()\n"
+"\tReturns the first parameter of the active distribution. Refer\n"
+"\tto the documentation of the generator types for the meaning\n"
+"\tof this value.";
+PyObject* SCA_RandomActuator::PyGetPara2(PyObject* self, PyObject* args, PyObject* kwds) {
+ return PyFloat_FromDouble(m_parameter2);
+}
+
+/* 8. getDistribution */
+char SCA_RandomActuator::GetDistribution_doc[] =
+"getDistribution()\n"
+"\tReturns the type of the active distribution.\n";
+PyObject* SCA_RandomActuator::PyGetDistribution(PyObject* self, PyObject* args, PyObject* kwds) {
+ return PyInt_FromLong(m_distribution);
+}
+
+/* 9. setProperty */
+char SCA_RandomActuator::SetProperty_doc[] =
+"setProperty(name)\n"
+"\t- name: string\n"
+"\tSet the property to which the random value is assigned. If the \n"
+"\tgenerator and property types do not match, the assignment is ignored.\n";
+PyObject* SCA_RandomActuator::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) {
+ char *nameArg;
+ if (!PyArg_ParseTuple(args, "s", &nameArg)) {
+ return NULL;
+ }
+
+ CValue* prop = GetParent()->FindIdentifier(nameArg);
+
+ if (prop) {
+ m_propname = nameArg;
+ prop->Release();
+ } else {
+ ; /* not found ... */
+ }
+
+ Py_Return;
+}
+/* 10. getProperty */
+char SCA_RandomActuator::GetProperty_doc[] =
+"getProperty(name)\n"
+"\tReturn the property to which the random value is assigned. If the \n"
+"\tgenerator and property types do not match, the assignment is ignored.\n";
+PyObject* SCA_RandomActuator::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) {
+ return PyString_FromString(m_propname);
+}
+
+/* 11. setBoolConst */
+char SCA_RandomActuator::SetBoolConst_doc[] =
+"setBoolConst(value)\n"
+"\t- value: 0 or 1\n"
+"\tSet this generator to produce a constant boolean value.\n";
+PyObject* SCA_RandomActuator::PySetBoolConst(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int paraArg;
+ if(!PyArg_ParseTuple(args, "i", &paraArg)) {
+ return NULL;
+ }
+
+ m_distribution = KX_RANDOMACT_BOOL_CONST;
+ if (paraArg) {
+ m_parameter1 = 1;
+ }
+
+ Py_Return;
+}
+/* 12. setBoolUniform, */
+char SCA_RandomActuator::SetBoolUniform_doc[] =
+"setBoolUniform()\n"
+"\tSet this generator to produce true and false, each with 50%% chance of occuring\n";
+PyObject* SCA_RandomActuator::PySetBoolUniform(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ /* no args */
+ m_distribution = KX_RANDOMACT_BOOL_UNIFORM;
+ enforceConstraints();
+ Py_Return;
+}
+/* 13. setBoolBernouilli, */
+char SCA_RandomActuator::SetBoolBernouilli_doc[] =
+"setBoolBernouilli(value)\n"
+"\t- value: a float between 0 and 1\n"
+"\tReturn false value * 100%% of the time.\n";
+PyObject* SCA_RandomActuator::PySetBoolBernouilli(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float paraArg;
+ if(!PyArg_ParseTuple(args, "f", &paraArg)) {
+ return NULL;
+ }
+
+ m_distribution = KX_RANDOMACT_BOOL_BERNOUILLI;
+ m_parameter1 = paraArg;
+ enforceConstraints();
+ Py_Return;
+}
+/* 14. setIntConst,*/
+char SCA_RandomActuator::SetIntConst_doc[] =
+"setIntConst(value)\n"
+"\t- value: integer\n"
+"\tAlways return value\n";
+PyObject* SCA_RandomActuator::PySetIntConst(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int paraArg;
+ if(!PyArg_ParseTuple(args, "i", &paraArg)) {
+ return NULL;
+ }
+
+ m_distribution = KX_RANDOMACT_INT_CONST;
+ m_parameter1 = paraArg;
+ enforceConstraints();
+ Py_Return;
+}
+/* 15. setIntUniform,*/
+char SCA_RandomActuator::SetIntUniform_doc[] =
+"setIntUniform(lower_bound, upper_bound)\n"
+"\t- lower_bound: integer\n"
+"\t- upper_bound: integer\n"
+"\tReturn a random integer between lower_bound and\n"
+"\tupper_bound. The boundaries are included.\n";
+PyObject* SCA_RandomActuator::PySetIntUniform(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int paraArg1, paraArg2;
+ if(!PyArg_ParseTuple(args, "ii", &paraArg1, &paraArg2)) {
+ return NULL;
+ }
+
+ m_distribution = KX_RANDOMACT_INT_UNIFORM;
+ m_parameter1 = paraArg1;
+ m_parameter2 = paraArg2;
+ enforceConstraints();
+ Py_Return;
+}
+/* 16. setIntPoisson, */
+char SCA_RandomActuator::SetIntPoisson_doc[] =
+"setIntPoisson(value)\n"
+"\t- value: float\n"
+"\tReturn a Poisson-distributed number. This performs a series\n"
+"\tof Bernouilli tests with parameter value. It returns the\n"
+"\tnumber of tries needed to achieve succes.\n";
+PyObject* SCA_RandomActuator::PySetIntPoisson(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float paraArg;
+ if(!PyArg_ParseTuple(args, "f", &paraArg)) {
+ return NULL;
+ }
+
+ m_distribution = KX_RANDOMACT_INT_POISSON;
+ m_parameter1 = paraArg;
+ enforceConstraints();
+ Py_Return;
+}
+/* 17. setFloatConst,*/
+char SCA_RandomActuator::SetFloatConst_doc[] =
+"setFloatConst(value)\n"
+"\t- value: float\n"
+"\tAlways return value\n";
+PyObject* SCA_RandomActuator::PySetFloatConst(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float paraArg;
+ if(!PyArg_ParseTuple(args, "f", &paraArg)) {
+ return NULL;
+ }
+
+ m_distribution = KX_RANDOMACT_FLOAT_CONST;
+ m_parameter1 = paraArg;
+ enforceConstraints();
+ Py_Return;
+}
+/* 18. setFloatUniform, */
+char SCA_RandomActuator::SetFloatUniform_doc[] =
+"setFloatUniform(lower_bound, upper_bound)\n"
+"\t- lower_bound: float\n"
+"\t- upper_bound: float\n"
+"\tReturn a random integer between lower_bound and\n"
+"\tupper_bound.\n";
+PyObject* SCA_RandomActuator::PySetFloatUniform(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float paraArg1, paraArg2;
+ if(!PyArg_ParseTuple(args, "ff", &paraArg1, &paraArg2)) {
+ return NULL;
+ }
+
+ m_distribution = KX_RANDOMACT_FLOAT_UNIFORM;
+ m_parameter1 = paraArg1;
+ m_parameter2 = paraArg2;
+ enforceConstraints();
+ Py_Return;
+}
+/* 19. setFloatNormal, */
+char SCA_RandomActuator::SetFloatNormal_doc[] =
+"setFloatNormal(mean, standard_deviation)\n"
+"\t- mean: float\n"
+"\t- standard_deviation: float\n"
+"\tReturn normal-distributed numbers. The average is mean, and the\n"
+"\tdeviation from the mean is characterized by standard_deviation.\n";
+PyObject* SCA_RandomActuator::PySetFloatNormal(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float paraArg1, paraArg2;
+ if(!PyArg_ParseTuple(args, "ff", &paraArg1, &paraArg2)) {
+ return NULL;
+ }
+
+ m_distribution = KX_RANDOMACT_FLOAT_NORMAL;
+ m_parameter1 = paraArg1;
+ m_parameter2 = paraArg2;
+ enforceConstraints();
+ Py_Return;
+}
+/* 20. setFloatNegativeExponential, */
+char SCA_RandomActuator::SetFloatNegativeExponential_doc[] =
+"setFloatNegativeExponential(half_life)\n"
+"\t- half_life: float\n"
+"\tReturn negative-exponentially distributed numbers. The half-life 'time'\n"
+"\tis characterized by half_life.\n";
+PyObject* SCA_RandomActuator::PySetFloatNegativeExponential(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float paraArg;
+ if(!PyArg_ParseTuple(args, "f", &paraArg)) {
+ return NULL;
+ }
+
+ m_distribution = KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL;
+ m_parameter1 = paraArg;
+ enforceConstraints();
+ Py_Return;
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.h b/source/gameengine/GameLogic/SCA_RandomActuator.h
new file mode 100644
index 00000000000..4be7f2dbe9e
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_RandomActuator.h
@@ -0,0 +1,145 @@
+/**
+ * Draw a random number, and put it in a property
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_RANDOMACTUATOR
+#define __KX_RANDOMACTUATOR
+
+#include "SCA_IActuator.h"
+#include "SCA_RandomNumberGenerator.h"
+
+class SCA_RandomActuator : public SCA_IActuator
+{
+ Py_Header;
+ /** Property to assign to */
+ STR_String m_propname;
+
+ /** First parameter. The meaning of the parameters depends on the
+ * distribution */
+ float m_parameter1;
+ /** Second parameter. The meaning of the parameters depends on the
+ * distribution */
+ float m_parameter2;
+
+ /** The base generator */
+ SCA_RandomNumberGenerator *m_base;
+
+ /** just a generic, persistent counter */
+ int m_counter;
+
+ /** cache for the previous draw */
+ long m_previous;
+
+ /** apply constraints for the chosen distribution to the parameters */
+ void enforceConstraints(void);
+
+ public:
+
+ enum KX_RANDOMACT_MODE {
+ KX_RANDOMACT_NODEF,
+ KX_RANDOMACT_BOOL_CONST,
+ KX_RANDOMACT_BOOL_UNIFORM,
+ KX_RANDOMACT_BOOL_BERNOUILLI,
+ KX_RANDOMACT_INT_CONST,
+ KX_RANDOMACT_INT_UNIFORM,
+ KX_RANDOMACT_INT_POISSON,
+ KX_RANDOMACT_FLOAT_CONST,
+ KX_RANDOMACT_FLOAT_UNIFORM,
+ KX_RANDOMACT_FLOAT_NORMAL,
+ KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL,
+ KX_RANDOMACT_MAX
+ };
+ /** distribution type */
+ KX_RANDOMACT_MODE m_distribution;
+
+ SCA_RandomActuator(class SCA_IObject* gameobj,
+ long seed,
+ KX_RANDOMACT_MODE mode,
+ float para1,
+ float para2,
+ const STR_String &propName,
+ PyTypeObject* T=&Type);
+ virtual ~SCA_RandomActuator();
+ virtual bool Update();
+
+ virtual CValue* GetReplica();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ /* 1. setSeed */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetSeed);
+ /* 2. getSeed */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,GetSeed);
+ /* 3. setPara1 -removed- */
+ /* 4. getPara1 */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,GetPara1);
+ /* 5. setPara2 -removed- */
+ /* 6. getPara2 */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,GetPara2);
+ /* 7. setDistribution -removed- */
+ /* 8. getDistribution */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,GetDistribution);
+ /* 9. setProperty */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetProperty);
+ /* 10. getProperty */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,GetProperty);
+ /* 11. setBoolConst */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetBoolConst);
+ /* 12. setBoolUniform, */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetBoolUniform);
+ /* 13. setBoolBernouilli, */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetBoolBernouilli);
+ /* 14. setIntConst,*/
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetIntConst);
+ /* 15. setIntUniform,*/
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetIntUniform);
+ /* 16. setIntPoisson, */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetIntPoisson);
+ /* 17. setFloatConst,*/
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetFloatConst);
+ /* 18. setFloatUniform, */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetFloatUniform);
+ /* 19. setFloatNormal, */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetFloatNormal);
+ /* 20. setFloatNegativeExponential, */
+ KX_PYMETHOD_DOC(SCA_RandomActuator,SetFloatNegativeExponential);
+
+}; /* end of class KX_EditObjectActuator : public SCA_PropertyActuator */
+
+#endif
+
diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.cpp b/source/gameengine/GameLogic/SCA_RandomEventManager.cpp
new file mode 100644
index 00000000000..6bf10a83f55
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_RandomEventManager.cpp
@@ -0,0 +1,68 @@
+/**
+ * Manager for random events
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_RandomEventManager.h"
+#include "SCA_LogicManager.h"
+#include "SCA_ISensor.h"
+#include <vector>
+using namespace std;
+
+#include <iostream>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+SCA_RandomEventManager::SCA_RandomEventManager(class SCA_LogicManager* logicmgr)
+ : SCA_EventManager(RANDOM_EVENTMGR),
+ m_logicmgr(logicmgr)
+{
+}
+
+
+void SCA_RandomEventManager::NextFrame()
+{
+ for (vector<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++)
+ {
+ SCA_ISensor *sensor = *i;
+ sensor->Activate(m_logicmgr, NULL);
+ }
+}
+
+
+
+void SCA_RandomEventManager::RegisterSensor(SCA_ISensor* sensor)
+{
+ m_sensors.push_back(sensor);
+};
diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.h b/source/gameengine/GameLogic/SCA_RandomEventManager.h
new file mode 100644
index 00000000000..17b2894434d
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_RandomEventManager.h
@@ -0,0 +1,55 @@
+/**
+ * Manager for random events
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_RANDOMEVENTMGR
+#define __KX_RANDOMEVENTMGR
+
+#include "SCA_EventManager.h"
+#include <vector>
+
+using namespace std;
+
+class SCA_RandomEventManager : public SCA_EventManager
+{
+ class SCA_LogicManager* m_logicmgr;
+
+public:
+ SCA_RandomEventManager(class SCA_LogicManager* logicmgr);
+
+ virtual void NextFrame();
+ virtual void RegisterSensor(SCA_ISensor* sensor);
+};
+
+#endif //__KX_RANDOMEVENTMGR
+
diff --git a/source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp
new file mode 100644
index 00000000000..06b5cca6ce9
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp
@@ -0,0 +1,129 @@
+/**
+ * Generate random numbers that can be used by other components. We
+ * convert to different types/distributions elsewhere. This just
+ * delivers a clean, random bitvector.
+ *
+ * $Id$
+ */
+
+/* A C-program for MT19937: Real number version */
+/* genrand() generates one pseudorandom real number (double) */
+/* which is uniformly distributed on [0,1]-interval, for each */
+/* call. sgenrand(seed) set initial values to the working area */
+/* of 624 words. Before genrand(), sgenrand(seed) must be */
+/* called once. (seed is any 32-bit integer except for 0). */
+/* Integer generator is obtained by modifying two lines. */
+/* Coded by Takuji Nishimura, considering the suggestions by */
+/* Topher Cooper and Marc Rieffel in July-Aug. 1997. */
+
+/* This library is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU Library General Public */
+/* License as published by the Free Software Foundation; either */
+/* version 2 of the License, or (at your option) any later */
+/* version. */
+/* This library is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
+/* See the GNU Library General Public License for more details. */
+/* You should have received a copy of the GNU Library General */
+/* Public License along with this library; if not, write to the */
+/* Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */
+/* 02111-1307 USA */
+
+/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */
+/* When you use this, send an email to: matumoto@math.keio.ac.jp */
+/* with an appropriate reference to your work. */
+
+#include <limits.h>
+#include "SCA_RandomNumberGenerator.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* Period parameters */
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0df /* constant vector a */
+#define UPPER_MASK 0x80000000 /* most significant w-r bits */
+#define LOWER_MASK 0x7fffffff /* least significant r bits */
+
+/* Tempering parameters */
+#define TEMPERING_MASK_B 0x9d2c5680
+#define TEMPERING_MASK_C 0xefc60000
+#define TEMPERING_SHIFT_U(y) (y >> 11)
+#define TEMPERING_SHIFT_S(y) (y << 7)
+#define TEMPERING_SHIFT_T(y) (y << 15)
+#define TEMPERING_SHIFT_L(y) (y >> 18)
+
+SCA_RandomNumberGenerator::SCA_RandomNumberGenerator(long seed) {
+ // int mti = N + 1; /*unused*/
+ m_seed = seed;
+ SetStartVector();
+}
+
+SCA_RandomNumberGenerator::~SCA_RandomNumberGenerator() {
+ /* intentionally empty */
+}
+
+void SCA_RandomNumberGenerator::SetStartVector(void) {
+ /* setting initial seeds to mt[N] using */
+ /* the generator Line 25 of Table 1 in */
+ /* [KNUTH 1981, The Art of Computer Programming */
+ /* Vol. 2 (2nd Ed.), pp102] */
+ mt[0] = m_seed & 0xffffffff;
+ for (mti = 1; mti < N; mti++)
+ mt[mti] = (69069 * mt[mti-1]) & 0xffffffff;
+}
+
+long SCA_RandomNumberGenerator::GetSeed() { return m_seed; }
+void SCA_RandomNumberGenerator::SetSeed(long newseed)
+{
+ m_seed = newseed;
+ SetStartVector();
+}
+
+/**
+ * This is the important part: copied verbatim :)
+ */
+unsigned long SCA_RandomNumberGenerator::Draw() {
+ static unsigned long mag01[2] = { 0x0, MATRIX_A };
+ /* mag01[x] = x * MATRIX_A for x=0,1 */
+
+ unsigned long y;
+
+ if (mti >= N) { /* generate N words at one time */
+ int kk;
+
+ /* I set this in the constructor, so it is always satisfied ! */
+// if (mti == N+1) /* if sgenrand() has not been called, */
+// GEN_srand(4357); /* a default initial seed is used */
+
+ for (kk = 0; kk < N - M; kk++) {
+ y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+ mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1];
+ }
+ for (; kk < N-1; kk++) {
+ y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+ mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1];
+ }
+ y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+ mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1];
+
+ mti = 0;
+ }
+
+ y = mt[mti++];
+ y ^= TEMPERING_SHIFT_U(y);
+ y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
+ y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
+ y ^= TEMPERING_SHIFT_L(y);
+
+ return y;
+}
+
+float SCA_RandomNumberGenerator::DrawFloat() {
+ return ( (float) Draw()/ (unsigned long) 0xffffffff );
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_RandomNumberGenerator.h b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.h
new file mode 100644
index 00000000000..b6272a09c9f
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.h
@@ -0,0 +1,65 @@
+/**
+ * Generate random numbers that can be used by other components. Each
+ * generator needs its own generator, so that the seed can be set
+ * on a per-generator basis.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_RANDOMNUMBERGENERATOR
+#define __KX_RANDOMNUMBERGENERATOR
+
+class SCA_RandomNumberGenerator {
+
+ /** base seed */
+ long m_seed;
+
+ /* A bit silly.. The N parameter is a define in the .cpp file */
+ /** the array for the state vector */
+ /* unsigned long mt[N]; */
+ unsigned long mt[624];
+
+ /** mti==N+1 means mt[KX_MT_VectorLenght] is not initialized */
+ int mti; /* initialised in the cpp file */
+
+ /** Calculate a start vector */
+ void SetStartVector(void);
+ public:
+ SCA_RandomNumberGenerator(long seed);
+ ~SCA_RandomNumberGenerator();
+ unsigned long Draw();
+ float DrawFloat();
+ long GetSeed();
+ void SetSeed(long newseed);
+};
+
+#endif /* __KX_RANDOMNUMBERGENERATOR */
+
diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.cpp b/source/gameengine/GameLogic/SCA_RandomSensor.cpp
new file mode 100644
index 00000000000..f747504a697
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_RandomSensor.cpp
@@ -0,0 +1,195 @@
+/**
+ * Generate random pulses
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_RandomSensor.h"
+#include "SCA_EventManager.h"
+#include "SCA_RandomEventManager.h"
+#include "SCA_LogicManager.h"
+#include "ConstExpr.h"
+#include <iostream>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+SCA_RandomSensor::SCA_RandomSensor(SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ int startseed,
+ PyTypeObject* T)
+ : SCA_ISensor(gameobj,eventmgr, T)
+{
+ m_iteration = 0;
+ m_lastdraw = false;
+
+ m_basegenerator = new SCA_RandomNumberGenerator(startseed);
+ m_currentDraw = m_basegenerator->Draw();
+ RegisterToManager();
+}
+
+
+
+SCA_RandomSensor::~SCA_RandomSensor()
+{
+ /* Nothing to be done here. */
+}
+
+
+
+CValue* SCA_RandomSensor::GetReplica()
+{
+ CValue* replica = new SCA_RandomSensor(*this);
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+bool SCA_RandomSensor::IsPositiveTrigger()
+{
+ return (m_invert !=m_lastdraw);
+}
+
+
+bool SCA_RandomSensor::Evaluate(CValue* event)
+{
+ /* Random generator is the generator from Line 25 of Table 1 in */
+ /* [KNUTH 1981, The Art of Computer Programming Vol. 2 */
+ /* (2nd Ed.), pp102] */
+ /* It's a very simple max. length sequence generator. We can */
+ /* draw 32 bool values before having to generate the next */
+ /* sequence value. There are some theorems that will tell you */
+ /* this is a reasonable way of generating bools. Check Knuth. */
+ /* Furthermore, we only draw each <delay>-eth frame. */
+
+ bool drawResult = false;
+
+ if (m_iteration > 31) {
+ m_currentDraw = m_basegenerator->Draw();
+ drawResult = (m_currentDraw & 0x1) == 0;
+ m_iteration = 1;
+ } else {
+ drawResult = ((m_currentDraw >> m_iteration) & 0x1) == 0;
+ m_iteration++;
+ }
+
+ /* now pass this result to some controller */
+ m_lastdraw = drawResult;
+ return drawResult;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject SCA_RandomSensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_RandomSensor",
+ sizeof(SCA_RandomSensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_RandomSensor::Parents[] = {
+ &SCA_RandomSensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef SCA_RandomSensor::Methods[] = {
+ {"setSeed", (PyCFunction) SCA_RandomSensor::sPySetSeed, METH_VARARGS, SetSeed_doc},
+ {"getSeed", (PyCFunction) SCA_RandomSensor::sPyGetSeed, METH_VARARGS, GetSeed_doc},
+ {"getLastDraw", (PyCFunction) SCA_RandomSensor::sPyGetLastDraw, METH_VARARGS, GetLastDraw_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* SCA_RandomSensor::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_ISensor);
+}
+
+/* 1. setSeed */
+char SCA_RandomSensor::SetSeed_doc[] =
+"setSeed(seed)\n"
+"\t- seed: integer\n"
+"\tSet the initial seed of the generator. Equal seeds produce\n"
+"\tequal series. If the seed is 0, the generator will produce\n"
+"\tthe same value on every call.\n";
+PyObject* SCA_RandomSensor::PySetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
+ long seedArg;
+ if(!PyArg_ParseTuple(args, "i", &seedArg)) {
+ return NULL;
+ }
+
+ m_basegenerator->SetSeed(seedArg);
+
+ Py_Return;
+}
+
+/* 2. getSeed */
+char SCA_RandomSensor::GetSeed_doc[] =
+"getSeed()\n"
+"\tReturns the initial seed of the generator. Equal seeds produce\n"
+"\tequal series.\n";
+PyObject* SCA_RandomSensor::PyGetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
+ return PyInt_FromLong(m_basegenerator->GetSeed());
+}
+
+/* 3. getLastDraw */
+char SCA_RandomSensor::GetLastDraw_doc[] =
+"getLastDraw()\n"
+"\tReturn the last value that was drawn.\n";
+PyObject* SCA_RandomSensor::PyGetLastDraw(PyObject* self, PyObject* args, PyObject* kwds) {
+ return PyInt_FromLong(m_lastdraw);
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.h b/source/gameengine/GameLogic/SCA_RandomSensor.h
new file mode 100644
index 00000000000..1a3c0402e31
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_RandomSensor.h
@@ -0,0 +1,76 @@
+/**
+ * Generate random pulses
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_RANDOMSENSOR
+#define __KX_RANDOMSENSOR
+
+#include "SCA_ISensor.h"
+#include "BoolValue.h"
+#include "SCA_RandomNumberGenerator.h"
+
+class SCA_RandomSensor : public SCA_ISensor
+{
+ Py_Header;
+
+ unsigned int m_currentDraw;
+ int m_iteration;
+ SCA_RandomNumberGenerator *m_basegenerator;
+ bool m_lastdraw;
+public:
+ SCA_RandomSensor(class SCA_EventManager* rndmgr,
+ SCA_IObject* gameobj,
+ int startseed,
+ PyTypeObject* T=&Type);
+ virtual ~SCA_RandomSensor();
+ virtual CValue* GetReplica();
+ virtual bool Evaluate(CValue* event);
+ virtual bool IsPositiveTrigger();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ /* 1. setSeed */
+ KX_PYMETHOD_DOC(SCA_RandomSensor,SetSeed);
+ /* 2. getSeed */
+ KX_PYMETHOD_DOC(SCA_RandomSensor,GetSeed);
+ /* 3. getSeed */
+ KX_PYMETHOD_DOC(SCA_RandomSensor,GetLastDraw);
+
+};
+
+#endif //__KX_RANDOMSENSOR
+
diff --git a/source/gameengine/GameLogic/SCA_TimeEventManager.cpp b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp
new file mode 100644
index 00000000000..d97727d2a33
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp
@@ -0,0 +1,114 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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
+
+// This warning tells us about truncation of __long__ stl-generated names.
+// It can occasionally cause DevStudio to have internal compiler warnings.
+#pragma warning( disable : 4786 )
+#endif
+
+#include "SCA_TimeEventManager.h"
+
+#include "SCA_LogicManager.h"
+#include "FloatValue.h"
+
+SCA_TimeEventManager::SCA_TimeEventManager(SCA_LogicManager* logicmgr)
+: SCA_EventManager(TIME_EVENTMGR)
+{
+}
+
+
+
+SCA_TimeEventManager::~SCA_TimeEventManager()
+{
+ for (vector<CValue*>::iterator it = m_timevalues.begin();
+ !(it == m_timevalues.end()); it++)
+ {
+ (*it)->Release();
+ }
+}
+
+
+
+void SCA_TimeEventManager::RegisterSensor(SCA_ISensor* sensor)
+{
+ // not yet
+}
+
+
+
+void SCA_TimeEventManager::NextFrame(double curtime, double fixedtime)
+{
+ if (m_timevalues.size() > 0 && fixedtime > 0.0)
+ {
+ CFloatValue* floatval = new CFloatValue(curtime);
+
+ // update sensors, but ... need deltatime !
+ for (vector<CValue*>::iterator it = m_timevalues.begin();
+ !(it == m_timevalues.end()); it++)
+ {
+ float newtime = (*it)->GetNumber() + fixedtime;
+ floatval->SetFloat(newtime);
+ (*it)->SetValue(floatval);
+ }
+
+ floatval->Release();
+ }
+}
+
+
+
+void SCA_TimeEventManager::AddTimeProperty(CValue* timeval)
+{
+ timeval->AddRef();
+ m_timevalues.push_back(timeval);
+}
+
+
+
+void SCA_TimeEventManager::RemoveTimeProperty(CValue* timeval)
+{
+ for (vector<CValue*>::iterator it = m_timevalues.begin();
+ !(it == m_timevalues.end()); it++)
+ {
+ if ((*it) == timeval)
+ {
+ this->m_timevalues.erase(it);
+ timeval->Release();
+ break;
+ }
+ }
+}
diff --git a/source/gameengine/GameLogic/SCA_TimeEventManager.h b/source/gameengine/GameLogic/SCA_TimeEventManager.h
new file mode 100644
index 00000000000..388d9ce53bd
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_TimeEventManager.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 __KX_TIMEEVENTMANAGER
+#define __KX_TIMEEVENTMANAGER
+
+#include "SCA_EventManager.h"
+#include "Value.h"
+#include <vector>
+
+using namespace std;
+
+class SCA_TimeEventManager : public SCA_EventManager
+{
+ vector<CValue*> m_timevalues; // values that need their time updated regularly
+
+public:
+ SCA_TimeEventManager(class SCA_LogicManager* logicmgr);
+ virtual ~SCA_TimeEventManager();
+
+ virtual void NextFrame(double curtime, double fixedtime);
+ virtual void RegisterSensor(class SCA_ISensor* sensor);
+ void AddTimeProperty(CValue* timeval);
+ void RemoveTimeProperty(CValue* timeval);
+};
+
+#endif //__KX_TIMEEVENTMANAGER
+
diff --git a/source/gameengine/GameLogic/SConscript b/source/gameengine/GameLogic/SConscript
new file mode 100644
index 00000000000..7a2c3d91e72
--- /dev/null
+++ b/source/gameengine/GameLogic/SConscript
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('*.cpp') + env.Glob('Joystick/*.cpp')
+
+incs = '. #/source/kernel/gen_system #/intern/string'
+incs += ' #/source/gameengine/Expressions #/intern/moto/include'
+
+incs += ' ' + env['BF_PYTHON_INC']
+incs += ' ' + env['BF_SDL_INC']
+
+env.BlenderLib ( 'bf_logic', sources, Split(incs), [], libtype=['game','player'], priority=[30, 110] )
diff --git a/source/gameengine/GamePlayer/CMakeLists.txt b/source/gameengine/GamePlayer/CMakeLists.txt
new file mode 100644
index 00000000000..dbcdb64a0a4
--- /dev/null
+++ b/source/gameengine/GamePlayer/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(common ghost)
diff --git a/source/gameengine/GamePlayer/Makefile b/source/gameengine/GamePlayer/Makefile
new file mode 100644
index 00000000000..c9a568f708d
--- /dev/null
+++ b/source/gameengine/GamePlayer/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 *****
+#
+# Bounces make to subdirectories.
+
+include nan_definitions.mk
+
+SOURCEDIR = source/gameengine/GamePlayer
+DIR = $(OCGDIR)/gameengine/GamePlayer
+DIRS = common ghost
+
+ifneq ($(NAN_NO_PLUGIN),true)
+ifeq ($(OS),$(findstring $(OS), "freebsd irix windows"))
+ ifneq ($(FREE_WINDOWS),true)
+ DIRS += netscape
+ endif
+endif
+
+ifeq ($(OS),$(findstring $(OS), "linux"))
+ ifeq ($(CPU),i386)
+ DIRS += netscape
+ endif
+endif
+
+ifeq ($(OS),$(findstring $(OS), "solaris"))
+ ifeq ($(CPU),sparc)
+ DIRS += netscape
+ endif
+endif
+endif
+
+include nan_subdirs.mk
diff --git a/source/gameengine/GamePlayer/SConscript b/source/gameengine/GamePlayer/SConscript
new file mode 100644
index 00000000000..0b140bba8e7
--- /dev/null
+++ b/source/gameengine/GamePlayer/SConscript
@@ -0,0 +1,3 @@
+#!/usr/bin/python
+SConscript(['common/SConscript',
+ 'ghost/SConscript'])
diff --git a/source/gameengine/GamePlayer/common/CMakeLists.txt b/source/gameengine/GamePlayer/common/CMakeLists.txt
new file mode 100644
index 00000000000..f56fa512ab6
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/CMakeLists.txt
@@ -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) 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
+ bmfont.cpp
+ GPC_Canvas.cpp
+ GPC_Engine.cpp
+ GPC_KeyboardDevice.cpp
+ GPC_MouseDevice.cpp
+ GPC_PolygonMaterial.cpp
+ GPC_RawImage.cpp
+ GPC_RawLoadDotBlendArray.cpp
+ GPC_RawLogoArrays.cpp
+ GPC_RenderTools.cpp
+ GPC_System.cpp
+)
+
+SET(INC
+ .
+ ../../../../intern/string
+ ../../../../intern/ghost
+ ../../../../intern/guardedalloc
+ ../../../../intern/bmfont
+ ../../../../intern/moto/include
+ ../../../../intern/SoundSystem
+ ../../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer
+ ../../../../source/kernel/gen_system
+ ../../../../source/kernel/gen_messaging
+ ../../../../source/gameengine/Converter
+ ../../../../source/blender/imbuf
+ ../../../../source/gameengine/Ketsji
+ ../../../../source/blender/blenlib
+ ../../../../source/blender/blenkernel
+ ../../../../source/blender
+ ../../../../source/blender/include
+ ../../../../source/blender/makesdna
+ ../../../../source/gameengine/Rasterizer
+ ../../../../source/gameengine/GameLogic
+ ../../../../source/gameengine/Expressions
+ ../../../../source/gameengine/Network
+ ../../../../source/gameengine/SceneGraph
+ ../../../../source/gameengine/Physics/common
+ ../../../../source/gameengine/Physics/Sumo
+ ../../../../source/gameengine/Physics/Sumo/Fuzzics/include
+ ../../../../source/gameengine/Network/LoopBackNetwork
+ ../../../../source/gameengine/GamePlayer/ghost
+ ../../../../source/blender/misc
+ ../../../../source/blender/blenloader
+ ${PYTHON_INC}
+ ${SOLID_INC}
+ ${PNG_INC}
+ ${ZLIB_INC}
+)
+
+BLENDERLIB_NOLIST(gp_common "${SRC}" "${INC}")
+#env.BlenderLib (libname='gp_common', sources=source_files, includes=incs, defines = [], libtype='player', priority=5, compileflags=cflags)
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
new file mode 100644
index 00000000000..506b2fc423c
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
@@ -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): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include "png.h"
+
+#include "RAS_IPolygonMaterial.h"
+#include "GPC_Canvas.h"
+
+GPC_Canvas::TBannerId GPC_Canvas::s_bannerId = 0;
+
+
+GPC_Canvas::GPC_Canvas(
+ int width,
+ int height
+) :
+ m_width(width),
+ m_height(height),
+ m_bannersEnabled(false)
+{
+}
+
+
+GPC_Canvas::~GPC_Canvas()
+{
+ DisposeAllBanners();
+}
+
+
+// void GPC_Canvas::InitPostRenderingContext(void)
+// {
+// glViewport(0, 0, m_width, m_height);
+// glMatrixMode(GL_PROJECTION);
+// glLoadIdentity();
+
+// glOrtho(-2.0, 2.0, -2.0, 2.0, -20.0, 20.0);
+
+// glMatrixMode(GL_MODELVIEW);
+// glLoadIdentity();
+
+// glEnable(GL_DEPTH_TEST);
+
+// glDepthFunc(GL_LESS);
+
+// glShadeModel(GL_SMOOTH);
+// }
+
+void GPC_Canvas::Resize(int width, int height)
+{
+ m_width = width;
+ m_height = height;
+}
+
+void GPC_Canvas::EndFrame()
+{
+ if (m_bannersEnabled)
+ DrawAllBanners();
+}
+
+
+void GPC_Canvas::ClearColor(float r, float g, float b, float a)
+{
+ ::glClearColor(r,g,b,a);
+}
+
+void GPC_Canvas::SetViewPort(int x1, int y1, int x2, int y2)
+{
+ /* XXX, nasty, this needs to go somewhere else,
+ * but where... definitly need to clean up this
+ * whole canvas/rendertools mess.
+ */
+ glEnable(GL_SCISSOR_TEST);
+
+ glViewport(x1,y1,x2-x1 + 1,y2-y1 + 1);
+ glScissor(x1,y1,x2-x1 + 1,y2-y1 + 1);
+};
+
+
+void GPC_Canvas::ClearBuffer(
+ int type
+){
+
+ int ogltype = 0;
+ if (type & RAS_ICanvas::COLOR_BUFFER )
+ ogltype |= GL_COLOR_BUFFER_BIT;
+ if (type & RAS_ICanvas::DEPTH_BUFFER )
+ ogltype |= GL_DEPTH_BUFFER_BIT;
+
+ ::glClear(ogltype);
+}
+
+
+GPC_Canvas::TBannerId GPC_Canvas::AddBanner(
+ unsigned int bannerWidth, unsigned int bannerHeight,
+ unsigned int imageWidth, unsigned int imageHeight,
+ unsigned char* imageData,
+ TBannerAlignment alignment, bool enabled)
+{
+ TBannerData banner;
+
+ banner.alignment = alignment;
+ banner.enabled = enabled;
+ banner.displayWidth = bannerWidth;
+ banner.displayHeight = bannerHeight;
+ banner.imageWidth = imageWidth;
+ banner.imageHeight = imageHeight;
+ unsigned int bannerDataSize = imageWidth*imageHeight*4;
+ banner.imageData = new unsigned char [bannerDataSize];
+ ::memcpy(banner.imageData, imageData, bannerDataSize);
+ banner.textureName = 0;
+
+ m_banners.insert(TBannerMap::value_type(++s_bannerId, banner));
+ return s_bannerId;
+}
+
+
+void GPC_Canvas::DisposeBanner(TBannerId id)
+{
+ TBannerMap::iterator it = m_banners.find(id);
+ if (it != m_banners.end()) {
+ DisposeBanner(it->second);
+ m_banners.erase(it);
+ }
+}
+
+void GPC_Canvas::DisposeAllBanners()
+{
+ TBannerMap::iterator it = m_banners.begin();
+ while (it != m_banners.end()) {
+ DisposeBanner(it->second);
+ it++;
+ }
+}
+
+void GPC_Canvas::SetBannerEnabled(TBannerId id, bool enabled)
+{
+ TBannerMap::iterator it = m_banners.find(id);
+ if (it != m_banners.end()) {
+ it->second.enabled = enabled;
+ }
+}
+
+
+void GPC_Canvas::SetBannerDisplayEnabled(bool enabled)
+{
+ m_bannersEnabled = enabled;
+}
+
+
+void GPC_Canvas::DisposeBanner(TBannerData& banner)
+{
+ if (banner.imageData) {
+ delete [] banner.imageData;
+ banner.imageData = 0;
+ }
+ if (banner.textureName) {
+ ::glDeleteTextures(1, (GLuint*)&banner.textureName);
+ }
+}
+
+void GPC_Canvas::DrawAllBanners(void)
+{
+ if(!m_bannersEnabled || (m_banners.size() < 1))
+ return;
+
+ // Save the old rendering parameters.
+
+ CanvasRenderState render_state;
+ PushRenderState(render_state);
+
+ // Set up everything for banner display.
+
+ // Set up OpenGL matrices
+ SetOrthoProjection();
+ // Activate OpenGL settings needed for display of the texture
+ ::glDisable(GL_LIGHTING);
+ ::glDisable(GL_DEPTH_TEST);
+ ::glDisable(GL_FOG);
+ ::glEnable(GL_TEXTURE_2D);
+ ::glEnable(GL_BLEND);
+ ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ TBannerMap::iterator it = m_banners.begin();
+ while (it != m_banners.end()) {
+ if (it->second.enabled) {
+ DrawBanner(it->second);
+ }
+ it++;
+ }
+
+ PopRenderState(render_state);
+}
+
+
+void GPC_Canvas::DrawBanner(TBannerData& banner)
+{
+ if(!banner.enabled)
+ return;
+
+ // Set up coordinates
+ int coords[4][2];
+ if (banner.alignment == alignTopLeft) {
+ // Upper left
+ coords[0][0] = 0;
+ coords[0][1] = ((int)m_height)-banner.displayHeight;
+ coords[1][0] = banner.displayWidth;
+ coords[1][1] = ((int)m_height)-banner.displayHeight;
+ coords[2][0] = banner.displayWidth;
+ coords[2][1] = ((int)m_height);
+ coords[3][0] = 0;
+ coords[3][1] = ((int)m_height);
+ }
+ else {
+ // Lower right
+ coords[0][0] = (int)m_width - banner.displayWidth;
+ coords[0][1] = 0;
+ coords[1][0] = m_width;
+ coords[1][1] = 0;
+ coords[2][0] = m_width;
+ coords[2][1] = banner.displayHeight;
+ coords[3][0] = (int)m_width - banner.displayWidth;
+ coords[3][1] = banner.displayHeight;
+ }
+ // Set up uvs
+ int uvs[4][2] = {
+ { 0, 1},
+ { 1, 1},
+ { 1, 0},
+ { 0, 0}
+ };
+
+ if (!banner.textureName) {
+ ::glGenTextures(1, (GLuint*)&banner.textureName);
+ ::glBindTexture(GL_TEXTURE_2D, banner.textureName);
+ ::glTexImage2D(
+ GL_TEXTURE_2D, // target
+ 0, // level
+ 4, // components
+ banner.imageWidth, // width
+ banner.displayHeight, // height
+ 0, // border
+ GL_RGBA, // format
+ GL_UNSIGNED_BYTE, // type
+ banner.imageData); // image data
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ else {
+ ::glBindTexture(GL_TEXTURE_2D, banner.textureName);
+ }
+
+ // Draw the rectangle with the texture on it
+ ::glBegin(GL_QUADS);
+ ::glColor4f(1.f, 1.f, 1.f, 1.f);
+ ::glTexCoord2iv((GLint*)uvs[0]);
+ ::glVertex2iv((GLint*)coords[0]);
+ ::glTexCoord2iv((GLint*)uvs[1]);
+ ::glVertex2iv((GLint*)coords[1]);
+ ::glTexCoord2iv((GLint*)uvs[2]);
+ ::glVertex2iv((GLint*)coords[2]);
+ ::glTexCoord2iv((GLint*)uvs[3]);
+ ::glVertex2iv((GLint*)coords[3]);
+ ::glEnd();
+}
+
+ void
+GPC_Canvas::
+PushRenderState(
+ CanvasRenderState & render_state
+){
+#if 0
+
+ ::glMatrixMode(GL_PROJECTION);
+ ::glPushMatrix();
+ ::glMatrixMode(GL_MODELVIEW);
+ ::glPushMatrix();
+ ::glMatrixMode(GL_TEXTURE);
+ ::glPushMatrix();
+ // Save old OpenGL settings
+ ::glGetIntegerv(GL_LIGHTING, (GLint*)&(render_state.oldLighting));
+ ::glGetIntegerv(GL_DEPTH_TEST, (GLint*)&(render_state.oldDepthTest));
+ ::glGetIntegerv(GL_FOG, (GLint*)&(render_state.oldFog));
+ ::glGetIntegerv(GL_TEXTURE_2D, (GLint*)&(render_state.oldTexture2D));
+ ::glGetIntegerv(GL_BLEND, (GLint*)&(render_state.oldBlend));
+ ::glGetIntegerv(GL_BLEND_SRC, (GLint*)&(render_state.oldBlendSrc));
+ ::glGetIntegerv(GL_BLEND_DST, (GLint*)&(render_state.oldBlendDst));
+ ::glGetFloatv(GL_CURRENT_COLOR, render_state.oldColor);
+ ::glGetIntegerv(GL_DEPTH_WRITEMASK,(GLint*)&(render_state.oldWriteMask));
+#else
+
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+
+#endif
+}
+
+ void
+GPC_Canvas::
+PopRenderState(
+ const CanvasRenderState & render_state
+){
+#if 0
+ // Restore OpenGL settings
+ render_state.oldLighting ? ::glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING);
+ render_state.oldDepthTest ? ::glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
+ render_state.oldFog ? ::glEnable(GL_FOG) : ::glDisable(GL_FOG);
+ render_state.oldTexture2D ? ::glEnable(GL_TEXTURE_2D) : glDisable(GL_TEXTURE_2D);
+ render_state.oldBlend ? glEnable(GL_BLEND) : ::glDisable(GL_BLEND);
+ ::glBlendFunc((GLenum)render_state.oldBlendSrc, (GLenum)render_state.oldBlendDst);
+ render_state.oldWriteMask ? ::glEnable(GL_DEPTH_WRITEMASK) : glDisable(GL_DEPTH_WRITEMASK);
+
+ ::glColor4fv(render_state.oldColor);
+ // Restore OpenGL matrices
+ ::glMatrixMode(GL_TEXTURE);
+ ::glPopMatrix();
+ ::glMatrixMode(GL_PROJECTION);
+ ::glPopMatrix();
+ ::glMatrixMode(GL_MODELVIEW);
+ ::glPopMatrix();
+
+#else
+
+ glPopAttrib();
+#endif
+}
+
+ void
+GPC_Canvas::
+SetOrthoProjection(
+){
+ // Set up OpenGL matrices
+ ::glViewport(0, 0, m_width, m_height);
+ ::glScissor(0, 0, m_width, m_height);
+ ::glMatrixMode(GL_PROJECTION);
+ ::glLoadIdentity();
+ ::glOrtho(0, m_width, 0, m_height, -1, 1);
+ ::glMatrixMode(GL_MODELVIEW);
+ ::glLoadIdentity();
+ ::glMatrixMode(GL_TEXTURE);
+ ::glLoadIdentity();
+}
+
+ void
+GPC_Canvas::
+MakeScreenShot(
+ const char* filename
+){
+ png_structp png_ptr;
+ png_infop info_ptr;
+ unsigned char *pixels = 0;
+ png_bytepp row_pointers = 0;
+ int i, bytesperpixel = 3, color_type = PNG_COLOR_TYPE_RGB;
+ FILE *fp = 0;
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ std::cout << "Cannot png_create_write_struct." << std::endl;
+ return;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ std::cout << "Cannot png_create_info_struct." << std::endl;
+ return;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ delete [] pixels;
+ delete [] row_pointers;
+ // printf("Aborting\n");
+ if (fp) {
+ fflush(fp);
+ fclose(fp);
+ }
+ return;
+ }
+
+ // copy image data
+
+ pixels = new unsigned char[GetWidth() * GetHeight() * bytesperpixel * sizeof(unsigned char)];
+ if (!pixels) {
+ std::cout << "Cannot allocate pixels array" << std::endl;
+ return;
+ }
+
+ glReadPixels(0, 0, GetWidth(), GetHeight(), GL_RGB, GL_UNSIGNED_BYTE, pixels);
+
+ fp = fopen(filename, "wb");
+ if (!fp)
+ {
+ std::cout << "Couldn't open " << filename << " for writing." << std::endl;
+ longjmp(png_jmpbuf(png_ptr), 1);
+ }
+
+ 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,
+ GetWidth(),
+ GetHeight(),
+ 8,
+ color_type,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+ // write the file header information
+ png_write_info(png_ptr, info_ptr);
+
+ // allocate memory for an array of row-pointers
+ row_pointers = new png_bytep [(GetHeight() * sizeof(png_bytep))];
+ if (!row_pointers)
+ {
+ std::cout << "Cannot allocate row-pointers array" << std::endl;
+ longjmp(png_jmpbuf(png_ptr), 1);
+ }
+
+ // set the individual row-pointers to point at the correct offsets
+ for (i = 0; i < GetHeight(); i++) {
+ row_pointers[GetHeight()-1-i] = (png_bytep)
+ ((unsigned char *)pixels + (i * GetWidth()) * 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
+ delete [] (pixels);
+ delete [] (row_pointers);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ if (fp)
+ {
+ fflush(fp);
+ fclose(fp);
+ }
+}
+
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.h b/source/gameengine/GamePlayer/common/GPC_Canvas.h
new file mode 100644
index 00000000000..42e2d882e9a
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.h
@@ -0,0 +1,273 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 _GPC_CANVAS_H_
+#define _GPC_CANVAS_H_
+
+#include "RAS_ICanvas.h"
+#include "RAS_Rect.h"
+
+#if defined(WIN32) || defined(__APPLE__)
+ #ifdef WIN32
+ #pragma warning (disable:4786) // suppress stl-MSVC debug info warning
+ #include <windows.h>
+ #include <GL/gl.h>
+ #else // WIN32
+ // __APPLE__ is defined
+ #include <AGL/gl.h>
+ #endif // WIN32
+#else //defined(WIN32) || defined(__APPLE__)
+ #include <GL/gl.h>
+#endif //defined(WIN32) || defined(__APPLE__)
+
+#include <map>
+
+
+class GPC_Canvas : public RAS_ICanvas
+{
+public:
+ /**
+ * Used to position banners in the canvas.
+ */
+ typedef enum {
+ alignTopLeft,
+ alignBottomRight
+ } TBannerAlignment;
+
+ typedef int TBannerId;
+
+protected:
+ /**
+ * Used to store info for banners drawn on top of the canvas.
+ */
+ typedef struct {
+ /** Where the banner will be displayed. */
+ TBannerAlignment alignment;
+ /** Banner display enabled. */
+ bool enabled;
+ /** Banner display width. */
+ unsigned int displayWidth;
+ /** Banner display height. */
+ unsigned int displayHeight;
+ /** Banner image width. */
+ unsigned int imageWidth;
+ /** Banner image height. */
+ unsigned int imageHeight;
+ /** Banner image data. */
+ unsigned char* imageData;
+ /** Banner OpenGL texture name. */
+ unsigned int textureName;
+ } TBannerData;
+ typedef std::map<TBannerId, TBannerData> TBannerMap;
+
+ /** Width of the context. */
+ int m_width;
+ /** Height of the context. */
+ int m_height;
+ /** Rect that defines the area used for rendering,
+ relative to the context */
+ RAS_Rect m_displayarea;
+
+ /** Storage for the banners to display. */
+ TBannerMap m_banners;
+ /** State of banner display. */
+ bool m_bannersEnabled;
+
+public:
+
+ GPC_Canvas(int width, int height);
+
+ virtual ~GPC_Canvas();
+
+ void Resize(int width, int height);
+
+
+ /**
+ * @section Methods inherited from abstract base class RAS_ICanvas.
+ */
+
+ int
+ GetWidth(
+ ) const {
+ return m_width;
+ }
+
+ int
+ GetHeight(
+ ) const {
+ return m_height;
+ }
+
+ const
+ RAS_Rect &
+ GetDisplayArea(
+ ) const {
+ return m_displayarea;
+ };
+
+ RAS_Rect &
+ GetDisplayArea(
+ ) {
+ return m_displayarea;
+ };
+
+ void
+ BeginFrame(
+ ) {};
+
+ /**
+ * Draws overlay banners and progress bars.
+ */
+ void
+ EndFrame(
+ );
+
+ void SetViewPort(int x1, int y1, int x2, int y2);
+
+ void ClearColor(float r, float g, float b, float a);
+
+ /**
+ * @section Methods inherited from abstract base class RAS_ICanvas.
+ * Semantics are not yet honoured.
+ */
+
+ void SetMouseState(RAS_MouseState mousestate)
+ {
+ // not yet
+ }
+
+ void SetMousePosition(int x, int y)
+ {
+ // not yet
+ }
+
+ virtual void MakeScreenShot(const char* filename);
+
+ void ClearBuffer(int type);
+
+ /**
+ * @section Services provided by this class.
+ */
+
+ /**
+ * Enables display of a banner.
+ * The image data is copied inside.
+ * @param bannerWidth Display width of the banner.
+ * @param bannerHeight Display height of the banner.
+ * @param imageWidth Width of the banner image in pixels.
+ * @param imageHeight Height of the banner image in pixels.
+ * @param imageData Pointer to the pixels of the image to display.
+ * @param alignement Where the banner will be positioned on the canvas.
+ * @param enabled Whether the banner will be displayed intiallly.
+ * @return A banner id.
+ */
+ TBannerId AddBanner(
+ unsigned int bannerWidth, unsigned int bannerHeight,
+ unsigned int imageWidth, unsigned int imageHeight,
+ unsigned char* imageData, TBannerAlignment alignment = alignTopLeft,
+ bool enabled = true);
+
+ /**
+ * Disposes a banner.
+ * @param id Bannner to be disposed.
+ */
+ void DisposeBanner(TBannerId id);
+
+ /**
+ * Disposes all the banners.
+ */
+ void DisposeAllBanners();
+
+ /**
+ * Enables or disables display of a banner.
+ * @param id Banner id of the banner to be enabled/disabled.
+ * @param enabled New state of the banner.
+ */
+ void SetBannerEnabled(TBannerId id, bool enabled = true);
+
+ /**
+ * Enables or disables display of all banners.
+ * @param enabled New state of the banners.
+ */
+ void SetBannerDisplayEnabled(bool enabled = true);
+
+protected:
+ /**
+ * Disposes a banner.
+ * @param it Bannner to be disposed.
+ */
+ void DisposeBanner(TBannerData& banner);
+
+ /**
+ * Draws all the banners enabled.
+ */
+ void DrawAllBanners(void);
+
+ /**
+ * Draws a banner.
+ */
+ void DrawBanner(TBannerData& banner);
+
+ struct CanvasRenderState {
+ int oldLighting;
+ int oldDepthTest;
+ int oldFog;
+ int oldTexture2D;
+ int oldBlend;
+ int oldBlendSrc;
+ int oldBlendDst;
+ float oldColor[4];
+ int oldWriteMask;
+ };
+
+ void
+ PushRenderState(
+ CanvasRenderState & render_state
+ );
+ void
+ PopRenderState(
+ const CanvasRenderState & render_state
+ );
+
+ /**
+ * Set up an orthogonal viewing,model and texture matrix
+ * for banners and progress bars.
+ */
+ void
+ SetOrthoProjection(
+ );
+
+ static TBannerId s_bannerId;
+};
+
+#endif // _GPC_CANVAS_H_
+
diff --git a/source/gameengine/GamePlayer/common/GPC_Engine.cpp b/source/gameengine/GamePlayer/common/GPC_Engine.cpp
new file mode 100644
index 00000000000..0986b8cee55
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_Engine.cpp
@@ -0,0 +1,342 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 (disable:4786) // suppress stl-MSVC debug info warning
+#endif // WIN32
+
+#include <iostream>
+
+#include "BKE_blender.h" // initglobals()
+#include "BKE_global.h" // Global G
+#include "DNA_scene_types.h"
+#include "DNA_camera_types.h" // Camera
+#include "DNA_object_types.h" // Object
+
+#include "BLO_readfile.h"
+#include "BLI_blenlib.h"
+
+// include files needed by "KX_BlenderSceneConverter.h"
+
+#include "GEN_Map.h"
+#include "SCA_IActuator.h"
+#include "RAS_MeshObject.h"
+
+#include "KX_BlenderSceneConverter.h"
+#include "KX_KetsjiEngine.h"
+#include "NG_LoopBackNetworkDeviceInterface.h"
+
+#include "RAS_IRenderTools.h"
+#include "SND_DeviceManager.h"
+
+#include "GPC_Engine.h"
+#include "GPC_KeyboardDevice.h"
+#include "GPC_MouseDevice.h"
+#include "GPC_RawImage.h"
+#include "GPC_RawLoadDotBlendArray.h"
+
+
+
+GPC_Engine::GPC_Engine(char *customLoadingAnimationURL,
+ int foregroundColor, int backgroundColor, int frameRate) :
+ m_initialized(false), m_running(false), m_loading(false),
+ m_customLoadingAnimation(false), m_previousProgress(0.0),
+ m_system(NULL), m_keyboarddev(NULL),
+ m_mousedev(NULL), m_canvas(NULL), m_rendertools(NULL),
+ m_portal(NULL), m_sceneconverter(NULL), m_networkdev(NULL),
+ m_audiodevice(NULL), m_curarea(NULL),
+ m_customLoadingAnimationURL(NULL),
+ m_foregroundColor(foregroundColor), m_backgroundColor(backgroundColor),
+ m_frameRate(frameRate),
+ m_BlenderLogo(0), m_Blender3DLogo(0)/*, m_NaNLogo(0)*/
+{
+ if(customLoadingAnimationURL[0] != '\0')
+ {
+ m_customLoadingAnimationURL = new char[sizeof(customLoadingAnimationURL)];
+// not yet, need to be implemented first... m_customLoadingAnimation = true;
+ }
+
+ // load the Blender logo into memory
+ m_BlenderLogo = new GPC_RawImage();
+ // blender3d size is 115 x 32 so make resulting texture 128 x 128
+ if(!m_BlenderLogo->Load("BlenderLogo", 128, 128, GPC_RawImage::alignTopLeft, 8, 8))
+ m_BlenderLogo = 0;
+
+ // load the Blender3D logo into memory
+ m_Blender3DLogo = new GPC_RawImage();
+ // blender3d size is 136 x 11 so make resulting texture 256 x 256
+ if(!m_Blender3DLogo->Load("Blender3DLogo", 256, 256, GPC_RawImage::alignBottomRight, 8, 8))
+ m_Blender3DLogo = 0;
+
+#if 0
+ // obsolete logo
+ // load the NaN logo into memory
+ m_NaNLogo = new GPC_RawImage();
+ // blender3d size is 32 x 31 so make resulting texture 64 x 64
+ if(!m_NaNLogo->Load("NaNLogo", 64, 64, GPC_RawImage::alignBottomRight, 8, 8))
+ m_NaNLogo = 0;
+#endif
+}
+
+
+GPC_Engine::~GPC_Engine()
+{
+ // deleting everything in reverse order of creation
+#if 0
+// hmm deleted in Stop() delete m_portal;
+// hmm deleted in Stop() delete m_sceneconverter;
+ delete m_system;
+ delete m_networkdev;
+ delete m_rendertools;
+ delete m_canvas;
+ delete m_mousedev;
+ delete m_keyboarddev;
+// not yet used so be careful and not delete them
+// delete m_WaveCache;
+// delete m_curarea; // for future use, not used yet
+#endif
+ delete m_BlenderLogo;
+ delete m_Blender3DLogo;
+#if 0
+ delete m_NaNLogo;
+#endif
+}
+
+
+bool GPC_Engine::Start(char *filename)
+{
+ BlendReadError error;
+ BlendFileData *bfd= BLO_read_from_file(filename, &error);
+
+ if (!bfd) {
+ // XXX, deal with error here
+ cout << "Unable to load: " << filename << endl;
+ return false;
+ }
+
+ StartKetsji();
+
+ if(bfd->type == BLENFILETYPE_PUB)
+ m_canvas->SetBannerDisplayEnabled(false);
+
+ return true;
+}
+
+
+bool GPC_Engine::Start(unsigned char *blenderDataBuffer,
+ unsigned int blenderDataBufferSize)
+{
+ BlendReadError error;
+ BlendFileData *bfd= BLO_read_from_memory(blenderDataBuffer, blenderDataBufferSize, &error);
+
+ if (!bfd) {
+ // XXX, deal with error here
+ cout << "Unable to load. " << endl;
+ return false;
+ }
+
+ StartKetsji();
+
+ if(bfd->type == BLENFILETYPE_PUB)
+ m_canvas->SetBannerDisplayEnabled(false);
+
+ return true;
+}
+
+
+bool GPC_Engine::StartKetsji(void)
+{
+ STR_String startSceneName = G.scene->id.name + 2;
+/*
+ KX_KetsjiEngine* ketsjieng = new KX_KetsjiEngine(m_system);
+ m_portal = new KetsjiPortal(ketsjieng);
+ m_portal->setSecurity(psl_Highest);
+
+ KX_ISceneConverter *sceneconverter = new KX_BlenderSceneConverter(&G, ketsjieng);
+
+ m_portal->Enter(
+ startSceneName,
+ sceneconverter,
+ m_canvas,
+ m_rendertools,
+ m_keyboarddev,
+ m_mousedev,
+ m_networkdev,
+ m_audiodevice,
+ m_system);
+
+ m_system->SetMainLoop(m_portal->m_ketsjieng);
+
+ m_running = true;
+ */
+ return true;
+}
+
+
+void GPC_Engine::StartLoadingAnimation()
+{
+ if(m_customLoadingAnimation)
+ {
+ }
+ else
+ {
+ unsigned char *blenderDataBuffer;
+ int blenderDataBufferSize;
+ GetRawLoadingAnimation(&blenderDataBuffer, &blenderDataBufferSize);
+ if(!Start(blenderDataBuffer, blenderDataBufferSize))
+ cout << "something went wrong when starting the engine" << endl;
+ delete blenderDataBuffer; // created with 'new' in GetRawLoadingAnimation()
+ }
+}
+
+
+// will be platform dependant
+float GPC_Engine::DetermineProgress(void)
+{
+#if 0
+ float progress;
+ if ((m_blenderData.m_ulProgress > 0) &&
+ (m_blenderData.m_ulProgressMax != m_blenderData.m_ulProgress)) {
+ progress = (float)m_blenderData.m_ulProgress;
+ progress /= (float)m_blenderData.m_ulProgressMax;
+ }
+ else {
+ progress = 0.f;
+ }
+ progress *= 100.f;
+ return (unsigned int) progress ;
+#endif
+ return m_previousProgress + 0.01; // temporary TODO
+}
+
+
+void GPC_Engine::UpdateLoadingAnimation(void)
+{
+ //int delta;
+
+ float progress = DetermineProgress();
+
+ if(progress > m_previousProgress)
+ {
+// delta = progress - m_previousProgress;
+ m_previousProgress = progress;
+ if(m_previousProgress > 1.0)
+ m_previousProgress = 1.0; // limit to 1.0 (has to change !)
+// m_engine->m_previousProgress = 0.0;
+ }
+
+ STR_String to = "";
+ STR_String from = "";
+ STR_String subject = "progress";
+ STR_String body;
+ body.Format("%f", progress); // a number between 0.0 and 1.0
+
+ if(m_networkdev)
+ {
+ // Store a progress message in the network device.
+ NG_NetworkMessage* msg = new NG_NetworkMessage(to, from, subject, body);
+ m_networkdev->SendNetworkMessage(msg);
+ msg->Release();
+ }
+}
+
+
+void GPC_Engine::Stop()
+{
+ // only delete things that are created in StartKetsji()
+/* if(m_portal)
+ {
+ m_portal->Leave();
+ delete m_portal; // also gets rid of KX_KetsjiEngine (says Maarten)
+ m_portal = 0;
+ }
+*/ if(m_sceneconverter)
+ {
+ delete m_sceneconverter;
+ m_sceneconverter = 0;
+ }
+#if 0
+ if(m_frameTimerID)
+ {
+ ::KillTimer(0, m_frameTimerID);
+ m_frameTimerID = 0;
+ }
+ m_engineRunning = false;
+#endif
+
+ m_running = false;
+}
+
+
+void GPC_Engine::Exit()
+{
+ if(m_running)
+ Stop();
+
+ if (m_system) {
+ delete m_system;
+ m_system = 0;
+ }
+ if (m_keyboarddev) {
+ delete m_keyboarddev;
+ m_keyboarddev = 0;
+ }
+ if (m_mousedev) {
+ delete m_mousedev;
+ m_mousedev = 0;
+ }
+ if (m_canvas) {
+ delete m_canvas;
+ m_canvas = 0;
+ }
+ if (m_rendertools) {
+ delete m_rendertools;
+ m_rendertools = 0;
+ }
+ if (m_networkdev) {
+ delete m_networkdev;
+ m_networkdev = 0;
+ }
+
+ if (m_audiodevice)
+ {
+ SND_DeviceManager::Unsubscribe();
+ m_audiodevice = 0;
+ }
+
+ m_initialized = false;
+}
+
diff --git a/source/gameengine/GamePlayer/common/GPC_Engine.h b/source/gameengine/GamePlayer/common/GPC_Engine.h
new file mode 100644
index 00000000000..a1403839e16
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_Engine.h
@@ -0,0 +1,129 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __GPC_ENGINE_H
+#define __GPC_ENGINE_H
+
+#include "GPC_Canvas.h"
+#include "GPC_System.h"
+
+class GPC_KeyboardDevice;
+class GPC_MouseDevice;
+
+class RAS_IRenderTools;
+class KetsjiPortal;
+class KX_ISceneConverter;
+class NG_LoopBackNetworkDeviceInterface;
+class SND_IAudioDevice;
+class GPC_RawImage;
+
+
+class GPC_Engine
+{
+//protected:
+public:
+ /** Engine construction state. */
+ bool m_initialized;
+ /** Engine state. */
+ bool m_running;
+ /** loading state, ie a file is requested and is being loaded. Different
+ * from initialized and/or running */
+ bool m_loading;
+
+ bool m_customLoadingAnimation;
+
+ /** Last file download progress measurement. */
+ float m_previousProgress;
+
+ /** The game engine's system abstraction. */
+ GPC_System* m_system;
+ /** The game engine's keyboard abstraction. */
+ GPC_KeyboardDevice* m_keyboarddev;
+ /** The game engine's mouse abstraction. */
+ GPC_MouseDevice* m_mousedev;
+ /** The game engine's canvas abstraction. */
+ GPC_Canvas* m_canvas;
+ /** The game engine's platform dependent render tools. */
+ RAS_IRenderTools* m_rendertools;
+ /** The portal used to start the engine. */
+ KetsjiPortal* m_portal;
+ /** Converts Blender data files. */
+ KX_ISceneConverter* m_sceneconverter;
+ /** Network interface. */
+ NG_LoopBackNetworkDeviceInterface* m_networkdev;
+ /** Audiodevice interface */
+ SND_IAudioDevice* m_audiodevice;
+
+ struct ScrArea *m_curarea; // for future use, not used yet
+
+ char *m_customLoadingAnimationURL;
+ int m_foregroundColor;
+ int m_backgroundColor;
+ int m_frameRate;
+
+ GPC_RawImage *m_BlenderLogo;
+ GPC_Canvas::TBannerId m_BlenderLogoId;
+ GPC_RawImage *m_Blender3DLogo;
+ GPC_Canvas::TBannerId m_Blender3DLogoId;
+#if 0
+ GPC_RawImage *m_NaNLogo;
+ GPC_Canvas::TBannerId m_NaNLogoId;
+#endif
+
+public:
+ GPC_Engine(char *customLoadingAnimation,
+ int foregroundColor, int backgroundColor, int frameRate);
+ virtual ~GPC_Engine();
+ // Initialize() functions are not put here since they have
+ // different prototypes for Unix and Windows
+ void StartLoadingAnimation();
+ bool Start(char *filename); // file-on-disk starter
+ bool Start(unsigned char *blenderDataBuffer,
+ unsigned int blenderDataBufferSize); // file-in-memory starter
+
+ void Stop();
+ virtual void Exit();
+
+ bool Initialized(void) {return m_initialized;}
+ bool Loading(void) {return m_loading;}
+ bool Running(void) const {return m_running;}
+
+ virtual float DetermineProgress(void); // will be platform dependant
+ void UpdateLoadingAnimation(void);
+
+private:
+ bool StartKetsji(void);
+
+};
+
+#endif // __GPC_ENGINE_H
+
diff --git a/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp b/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp
new file mode 100644
index 00000000000..dbe875957b0
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp
@@ -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 *****
+ */
+
+#include "GPC_KeyboardDevice.h"
+
+/**
+ * NextFrame toggles currentTable with previousTable,
+ * and copies relevant event information from previous to current table
+ * (pressed keys need to be remembered).
+ */
+void GPC_KeyboardDevice::NextFrame()
+{
+ SCA_IInputDevice::NextFrame();
+
+ // Now convert justpressed key events into regular (active) keyevents
+ int previousTable = 1-m_currentTable;
+ for (int keyevent= KX_BEGINKEY; keyevent< KX_ENDKEY;keyevent++)
+ {
+ SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][keyevent];
+ if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED ||
+ oldevent.m_status == SCA_InputEvent::KX_ACTIVE )
+ {
+ m_eventStatusTables[m_currentTable][keyevent] = oldevent;
+ m_eventStatusTables[m_currentTable][keyevent].m_status = SCA_InputEvent::KX_ACTIVE;
+ //m_eventStatusTables[m_currentTable][keyevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED ;
+ }
+ }
+}
+
+
+
+/**
+ * ConvertBPEvent translates Windows keyboard events into ketsji kbd events.
+ * Extra event information is stored, like ramp-mode (just released/pressed)
+ */
+bool GPC_KeyboardDevice::ConvertEvent(int incode, int val)
+{
+ bool result = false;
+
+ // convert event
+ KX_EnumInputs kxevent = this->ToNative(incode);
+
+ // only process it, if it's a key
+ if (kxevent >= KX_BEGINKEY && kxevent < KX_ENDKEY)
+ {
+ int previousTable = 1-m_currentTable;
+
+ if (val > 0)
+ {
+ if (kxevent == SCA_IInputDevice::KX_ESCKEY && val != 0 && !m_hookesc)
+ result = true;
+
+ // todo: convert val ??
+ m_eventStatusTables[m_currentTable][kxevent].m_eventval = val ; //???
+
+ switch (m_eventStatusTables[previousTable][kxevent].m_status)
+ {
+ case SCA_InputEvent::KX_JUSTACTIVATED:
+ case SCA_InputEvent::KX_ACTIVE:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE;
+ break;
+ }
+
+ case SCA_InputEvent::KX_NO_INPUTSTATUS:
+ default:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED;
+ }
+ }
+
+ } else
+ {
+
+ switch (m_eventStatusTables[previousTable][kxevent].m_status)
+ {
+ case SCA_InputEvent::KX_JUSTACTIVATED:
+ case SCA_InputEvent::KX_ACTIVE:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTRELEASED;
+ break;
+ }
+ default:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS;
+ }
+ }
+ }
+ } else if(kxevent==KX_ENDKEY) {
+ exit(1);
+ }
+ return result;
+}
+
+void GPC_KeyboardDevice::HookEscape()
+{
+ m_hookesc = true;
+}
diff --git a/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.h b/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.h
new file mode 100644
index 00000000000..da3dc2398dd
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.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) 2001-2002 by 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 __GPC_KEYBOARDDEVICE_H
+#define __GPC_KEYBOARDDEVICE_H
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif // WIN32
+
+#include "SCA_IInputDevice.h"
+
+#include <map>
+
+
+/**
+ * System independent implementation of SCA_IInputDevice.
+ * System dependent keyboard devices need only to inherit this class
+ * and fill the m_reverseKeyTranslateTable key translation map.
+ * @see SCA_IInputDevice
+ */
+
+class GPC_KeyboardDevice : public SCA_IInputDevice
+{
+protected:
+
+ /**
+ * This map converts system dependent keyboard codes into Ketsji codes.
+ * System dependent keyboard codes are stored as ints.
+ */
+ std::map<int, KX_EnumInputs> m_reverseKeyTranslateTable;
+ bool m_hookesc;
+
+public:
+ GPC_KeyboardDevice()
+ : m_hookesc(false)
+ {
+ }
+
+ virtual ~GPC_KeyboardDevice(void)
+ {
+ }
+
+ virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode)
+ {
+ return false;
+ }
+
+ virtual void NextFrame();
+
+ virtual KX_EnumInputs ToNative(int incode)
+ {
+ return m_reverseKeyTranslateTable[incode];
+ }
+
+ virtual bool ConvertEvent(int incode, int val);
+
+ virtual void HookEscape();
+};
+
+#endif // _GPC_KEYBOARDDEVICE_H
+
diff --git a/source/gameengine/GamePlayer/common/GPC_MouseDevice.cpp b/source/gameengine/GamePlayer/common/GPC_MouseDevice.cpp
new file mode 100644
index 00000000000..7e57aa1ee40
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_MouseDevice.cpp
@@ -0,0 +1,216 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "GPC_MouseDevice.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+GPC_MouseDevice::GPC_MouseDevice()
+{
+
+}
+GPC_MouseDevice::~GPC_MouseDevice()
+{
+
+}
+
+/**
+ * IsPressed gives boolean information about mouse status, true if pressed, false if not.
+ */
+bool GPC_MouseDevice::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode)
+{
+ const SCA_InputEvent & inevent = m_eventStatusTables[m_currentTable][inputcode];
+ bool pressed = (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED ||
+ inevent.m_status == SCA_InputEvent::KX_ACTIVE);
+ return pressed;
+}
+
+
+/**
+ * NextFrame toggles currentTable with previousTable,
+ * and copies relevant event information from previous to current table
+ * (pressed keys need to be remembered).
+ */
+void GPC_MouseDevice::NextFrame()
+{
+ SCA_IInputDevice::NextFrame();
+
+ // Convert just pressed events into regular (active) events
+ int previousTable = 1-m_currentTable;
+ for (int mouseevent= KX_BEGINMOUSE; mouseevent< KX_ENDMOUSEBUTTONS; mouseevent++) {
+ SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][mouseevent];
+ if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED ||
+ oldevent.m_status == SCA_InputEvent::KX_ACTIVE) {
+ m_eventStatusTables[m_currentTable][mouseevent] = oldevent;
+ m_eventStatusTables[m_currentTable][mouseevent].m_status = SCA_InputEvent::KX_ACTIVE;
+ }
+ }
+ for (int mousemove= KX_ENDMOUSEBUTTONS; mousemove< KX_ENDMOUSE; mousemove++) {
+ SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][mousemove];
+ m_eventStatusTables[m_currentTable][mousemove] = oldevent;
+ if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED ||
+ oldevent.m_status == SCA_InputEvent::KX_ACTIVE) {
+ m_eventStatusTables[m_currentTable][mousemove].m_status = SCA_InputEvent::KX_JUSTRELEASED;
+ }
+ else {
+ if (oldevent.m_status == SCA_InputEvent::KX_JUSTRELEASED) {
+ m_eventStatusTables[m_currentTable][mousemove].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS ;
+ }
+ }
+ }
+}
+
+
+bool GPC_MouseDevice::ConvertButtonEvent(TButtonId button, bool isDown)
+{
+ bool result = false;
+
+ switch (button)
+ {
+ case buttonLeft:
+ result = ConvertEvent(KX_LEFTMOUSE, isDown);
+ break;
+ case buttonMiddle:
+ result = ConvertEvent(KX_MIDDLEMOUSE, isDown);
+ break;
+ case buttonRight:
+ result = ConvertEvent(KX_RIGHTMOUSE, isDown);
+ break;
+ case buttonWheelUp:
+ result = ConvertEvent(KX_WHEELUPMOUSE, isDown);
+ break;
+ case buttonWheelDown:
+ result = ConvertEvent(KX_WHEELDOWNMOUSE, isDown);
+ break;
+ default:
+ // Should not happen!
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * Splits combined button and x,y cursor move events into separate Ketsji
+ * x and y move and button events.
+ */
+bool GPC_MouseDevice::ConvertButtonEvent(TButtonId button, bool isDown, int x, int y)
+{
+ // First update state tables for cursor move.
+ bool result = ConvertMoveEvent(x, y);
+
+ // Now update for button state.
+ if (result) {
+ result = ConvertButtonEvent(button, isDown);
+ }
+
+ return result;
+}
+
+/**
+ * Splits combined x,y move into separate Ketsji x and y move events.
+ */
+bool GPC_MouseDevice::ConvertMoveEvent(int x, int y)
+{
+ bool result;
+
+ // Convert to local coordinates?
+ result = ConvertEvent(KX_MOUSEX, x);
+ if (result) {
+ result = ConvertEvent(KX_MOUSEY, y);
+ }
+
+ return result;
+}
+
+
+bool GPC_MouseDevice::ConvertEvent(KX_EnumInputs kxevent, int eventval)
+{
+ bool result = true;
+
+ // Only process it, if it's a mouse event
+ if (kxevent > KX_BEGINMOUSE && kxevent < KX_ENDMOUSE) {
+ int previousTable = 1-m_currentTable;
+
+ if (eventval > 0) {
+ m_eventStatusTables[m_currentTable][kxevent].m_eventval = eventval;
+
+ switch (m_eventStatusTables[previousTable][kxevent].m_status)
+ {
+ case SCA_InputEvent::KX_ACTIVE:
+ case SCA_InputEvent::KX_JUSTACTIVATED:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE;
+ break;
+ }
+ case SCA_InputEvent::KX_JUSTRELEASED:
+ {
+ if ( kxevent > KX_BEGINMOUSEBUTTONS && kxevent < KX_ENDMOUSEBUTTONS)
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED;
+ } else
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE;
+
+ }
+ break;
+ }
+ default:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED;
+ }
+ }
+
+ }
+ else {
+ switch (m_eventStatusTables[previousTable][kxevent].m_status)
+ {
+ case SCA_InputEvent::KX_JUSTACTIVATED:
+ case SCA_InputEvent::KX_ACTIVE:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTRELEASED;
+ break;
+ }
+ default:
+ {
+ m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS;
+ }
+ }
+ }
+ }
+ else {
+ result = false;
+ }
+ return result;
+}
diff --git a/source/gameengine/GamePlayer/common/GPC_MouseDevice.h b/source/gameengine/GamePlayer/common/GPC_MouseDevice.h
new file mode 100644
index 00000000000..da5098b06d6
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_MouseDevice.h
@@ -0,0 +1,107 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __GPC_MOUSE_DEVICE_H
+#define __GPC_MOUSE_DEVICE_H
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif // WIN32
+
+#include "SCA_IInputDevice.h"
+
+
+/**
+ * Generic Ketsji mouse device.
+ * @see SCA_IInputDevice
+ */
+class GPC_MouseDevice : public SCA_IInputDevice
+{
+public:
+ /**
+ * Button identifier.
+ */
+ typedef enum {
+ buttonLeft,
+ buttonMiddle,
+ buttonRight,
+ buttonWheelUp,
+ buttonWheelDown
+ } TButtonId;
+
+ GPC_MouseDevice();
+ virtual ~GPC_MouseDevice(void);
+
+ virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode);
+ virtual void NextFrame();
+
+ /**
+ * Call this routine to update the mouse device when a button state changes.
+ * @param button Which button state changes.
+ * @param isDown The new state of the button.
+ * @param x Position x-coordinate of the cursor at the time of the state change.
+ * @param y Position y-coordinate of the cursor at the time of the state change.
+ * @return Indication as to whether the event was processed.
+ */
+ virtual bool ConvertButtonEvent(TButtonId button, bool isDown);
+
+ /**
+ * Call this routine to update the mouse device when a button state and
+ * cursor position changes at the same time (e.g. in Win32 messages).
+ * @param button Which button state changes.
+ * @param isDown The new state of the button.
+ * @param x Position x-coordinate of the cursor at the time of the state change.
+ * @param y Position y-coordinate of the cursor at the time of the state change.
+ * @return Indication as to whether the event was processed.
+ */
+ virtual bool ConvertButtonEvent(TButtonId button, bool isDown, int x, int y);
+
+ /**
+ * Call this routine to update the mouse device when the cursor has moved.
+ * @param x Position x-coordinate of the cursor.
+ * @param y Position y-coordinate of the cursor.
+ * @return Indication as to whether the event was processed.
+ */
+ virtual bool ConvertMoveEvent(int x, int y);
+
+protected:
+ /**
+ * This routine converts a single mouse event to a Ketsji mouse event.
+ * @param kxevent Ketsji event code.
+ * @param eventval Value for this event.
+ * @return Indication as to whether the event was processed.
+ */
+ virtual bool ConvertEvent(KX_EnumInputs kxevent, int eventval);
+};
+
+#endif // __GPC_MOUSE_DEVICE_H
+
diff --git a/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.cpp b/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.cpp
new file mode 100644
index 00000000000..5b3c2c84edb
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.cpp
@@ -0,0 +1,421 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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
+#include <windows.h>
+#endif // WIN32
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif
+
+
+
+#include "GPC_PolygonMaterial.h"
+#include "MT_Vector3.h"
+#include "RAS_IRasterizer.h"
+#include "RAS_GLExtensionManager.h"
+
+/* This list includes only data type definitions */
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_group_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_property_types.h"
+#include "DNA_text_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_actuator_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_mesh.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "IMB_imbuf_types.h"
+/* end of blender include block */
+
+static Image *fCurpage=0;
+static int fCurtile=0, fCurmode=0, fCurTileXRep=0, fCurTileYRep=0;
+static short fTexWindx, fTexWindy, fTexWinsx, fTexWinsy;
+static int fDoMipMap = 1;
+static int fLinearMipMap=1;
+static int fAlphamode= -1;
+
+using namespace bgl;
+ /* (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;
+}
+
+static void my_make_repbind(Image *ima)
+{
+ if(ima==0 || ima->ibufs.first==0) return;
+
+ if(ima->repbind) {
+ glDeleteTextures(ima->totbind, (GLuint*)ima->repbind);
+ delete (ima->repbind);
+ ima->repbind= 0;
+ }
+ ima->totbind= ima->xrep*ima->yrep;
+ if(ima->totbind>1) {
+ ima->repbind= (unsigned int *) malloc(sizeof(int)*ima->totbind);
+ for (int i=0;i<ima->totbind;i++)
+ ((int*)ima->repbind)[i] = 0;
+ }
+}
+
+extern "C" int set_tpage(MTFace *tface);
+
+int set_tpage(MTFace *tface)
+{
+ static MTFace *lasttface= 0;
+ Image *ima;
+ unsigned int *rect, *bind;
+ int tpx, tpy, 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;
+ fAlphamode= -1;
+
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ return 0;
+ }
+ lasttface= tface;
+
+ if( fAlphamode != tface->transp) {
+ fAlphamode= tface->transp;
+
+ if(fAlphamode) {
+ glEnable(GL_BLEND);
+
+ if(fAlphamode==TF_ADD) {
+ glBlendFunc(GL_ONE, GL_ONE);
+ /* glBlendEquationEXT(GL_FUNC_ADD_EXT); */
+ }
+ else if(fAlphamode==TF_ALPHA) {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ /* glBlendEquationEXT(GL_FUNC_ADD_EXT); */
+ }
+ /* else { */
+ /* glBlendFunc(GL_ONE, GL_ONE); */
+ /* glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); */
+ /* } */
+ }
+ else glDisable(GL_BLEND);
+ }
+
+ ima= (struct Image *) tface->tpage;
+
+ /* Enable or disable environment mapping */
+ if (ima && (ima->flag & IMA_REFLECT)){
+
+ 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);
+ }
+ 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!=0)
+ glScalef(ima->xrep, ima->yrep, 1.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ }
+
+ if(ima==0 || ima->ok==0) {
+ glDisable(GL_TEXTURE_2D);
+
+ fCurtile= tface->tile;
+ fCurpage= 0;
+ fCurmode= tilemode;
+ fCurTileXRep = tileXRep;
+ fCurTileYRep = tileYRep;
+
+ return 0;
+ }
+
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+
+ if(ibuf==0) {
+ ima->ok= 0;
+
+ fCurtile= tface->tile;
+ fCurpage= 0;
+ fCurmode= tilemode;
+ fCurTileXRep = tileXRep;
+ fCurTileYRep = tileYRep;
+
+ glDisable(GL_TEXTURE_2D);
+ return 0;
+ }
+
+ if(ima->tpageflag & IMA_TWINANIM) fCurtile= ima->lastframe;
+ else fCurtile= tface->tile;
+
+ if(tilemode) {
+
+ if(ima->repbind==0) my_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= (unsigned int*)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(rectw) || !is_pow2(recth)) {
+ rectw= smaller_pow2(rectw);
+ recth= smaller_pow2(recth);
+
+ scalerect= (unsigned int *)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) {
+ printf("var1: %s\n", ima->id.name+2);
+ printf("var1: %d, var2: %d\n", *bind, tpx);
+ printf("var1: %d, var2: %d\n", fCurtile, tilemode);
+ }
+ */
+ glBindTexture( GL_TEXTURE_2D, *bind);
+
+ if (!fDoMipMap)
+ {
+ 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);
+ }
+
+ 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);
+
+
+
+ glEnable(GL_TEXTURE_2D);
+
+ fCurpage= ima;
+ fCurmode= tilemode;
+ fCurTileXRep = tileXRep;
+ fCurTileYRep = tileYRep;
+
+ return 1;
+}
+
+#if 0
+GPC_PolygonMaterial::GPC_PolygonMaterial(const STR_String& texname, bool ba, const STR_String& matname,
+ int tile, int tileXrep, int tileYrep, int mode, bool transparant, bool zsort,
+ int lightlayer, bool bIsTriangle, void* clientobject, void* tpage) :
+ RAS_IPolyMaterial(texname, ba, matname, tile, tileXrep, tileYrep, mode,
+ transparant, zsort, lightlayer, bIsTriangle, clientobject), m_tface((struct MTFace*)tpage)
+{
+ // clear local caching info
+ my_set_tpage(0);
+}
+
+
+GPC_PolygonMaterial::~GPC_PolygonMaterial(void)
+{
+}
+
+
+void GPC_PolygonMaterial::Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const
+{
+ if (GetCachingInfo() != cachingInfo)
+ {
+ if (!cachingInfo)
+ {
+ my_set_tpage(0);
+ }
+ cachingInfo = GetCachingInfo();
+
+ if ((m_drawingmode & 4)&& (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) )
+ {
+ update_realtime_texture((struct MTFace*) m_tface, rasty->GetTime());
+ my_set_tpage(m_tface);
+ rasty->EnableTextures(true);
+ } else
+ {
+ my_set_tpage(0);
+ rasty->EnableTextures(false);
+ }
+
+ //TF_TWOSIDE == 512, todo, make this a ketsji enum
+ if(m_drawingmode & 512) {
+ rasty->SetCullFace(false);
+ }
+
+ else
+ {
+ rasty->SetCullFace(true);//glEnable(GL_CULL_FACE);
+ //else glDisable(GL_CULL_FACE);
+ }
+ }
+ rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity);
+ rasty->SetShinyness(m_shininess);
+ rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0);
+}
+
+#endif
+void GPC_PolygonMaterial::SetMipMappingEnabled(bool enabled)
+{
+ fDoMipMap = enabled ? 1 : 0;
+}
diff --git a/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.h b/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.h
new file mode 100644
index 00000000000..d9aa3ca4b7e
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.h
@@ -0,0 +1,92 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __GPC_POLYGONMATERIAL
+#define __GPC_POLYGONMATERIAL
+
+#include "RAS_IPolygonMaterial.h"
+
+namespace GPC_PolygonMaterial
+{
+ void SetMipMappingEnabled(bool enabled = false);
+};
+
+#if 0
+class GPC_PolygonMaterial : public RAS_IPolyMaterial
+{
+ struct MTFace* m_tface;
+
+public:
+ GPC_PolygonMaterial(const STR_String& texname, bool ba, const STR_String& matname,
+ int tile, int tileXrep, int tileYrep, int mode, bool transparant, bool zsort,
+ int lightlayer, bool bIsTriangle, void* clientobject, void* tpage);
+
+ virtual ~GPC_PolygonMaterial(void);
+
+ /**
+ * Returns the caching information for this material,
+ * This can be used to speed up the rasterizing process.
+ * @return The caching information.
+ */
+ virtual TCachingInfo GetCachingInfo(void) const;
+
+ /**
+ * Activates the material in the (OpenGL) rasterizer.
+ * On entry, the cachingInfo contains info about the last activated material.
+ * On exit, the cachingInfo should contain updated info about this material.
+ * @param rasty The rasterizer in which the material should be active.
+ * @param cachingInfo The information about the material used to speed up rasterizing.
+ */
+ virtual void Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const;
+
+ /**
+ * Returns the Blender texture face structure that is used for this material.
+ * @return The material's texture face.
+ */
+ MTFace* GetMTFace(void) const;
+
+ static void SetMipMappingEnabled(bool enabled = false);
+};
+
+
+inline MTFace* GPC_PolygonMaterial::GetMTFace(void) const
+{
+ return m_tface;
+}
+
+inline GPC_PolygonMaterial::TCachingInfo GPC_PolygonMaterial::GetCachingInfo(void) const
+{
+ return GetMTFace();
+}
+#endif
+#endif // __GPC_POLYGONMATERIAL_H
+
diff --git a/source/gameengine/GamePlayer/common/GPC_RawImage.cpp b/source/gameengine/GamePlayer/common/GPC_RawImage.cpp
new file mode 100644
index 00000000000..7d0886a292b
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_RawImage.cpp
@@ -0,0 +1,138 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 <iostream>
+#include <string.h>
+
+#include "GPC_RawImage.h"
+#include "GPC_RawLogoArrays.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+GPC_RawImage::GPC_RawImage()
+ : m_data(0), m_dataSize(0), m_width(0), m_height(0)
+{
+}
+
+
+bool GPC_RawImage::Load(
+ char *srcName,
+ int destWidth, int destHeight,
+ TImageAlignment alignment, int offsetX, int offsetY)
+{
+ int srcWidth, srcHeight;
+ bool success = true;
+ if(strcmp(srcName, "BlenderLogo") == 0)
+ GetRawBlenderLogo(&m_data, &srcWidth, &srcHeight);
+ else
+ if(strcmp(srcName, "Blender3DLogo") == 0)
+ GetRawBlender3DLogo(&m_data, &srcWidth, &srcHeight);
+#if 0
+ else
+ if(strcmp(srcName, "NaNLogo") == 0)
+ GetRawNaNLogo(&m_data, &srcWidth, &srcHeight);
+#endif
+ else // unknown image
+ success = false;
+
+ if(success)
+ {
+ unsigned char *tempData = m_data;
+
+ int numBytes = destWidth * destHeight * 4;
+ m_data = new unsigned char[numBytes]; // re-use m_data ('unsigned char' was 'char')
+ if(m_data)
+ {
+ ::memset(m_data, 0x00000000, numBytes);
+ m_width = destWidth;
+ m_height = destHeight;
+
+ int srcBytesWidth = srcWidth * 4;
+ int dstBytesWidth = m_width * 4;
+ int numRows = (srcHeight + offsetY) < m_height ? srcHeight : m_height - offsetY;
+ numBytes = (srcWidth + offsetX) < m_width ? srcBytesWidth : (m_width - offsetX) * 4;
+
+ if((offsetX < m_width) && (offsetY < m_height))
+ {
+ unsigned char* src = (unsigned char*)tempData;
+ unsigned char* dst = (unsigned char*)m_data;
+ if(alignment == alignTopLeft)
+ {
+ // Put original in upper left corner
+
+ // Add vertical offset
+ dst += offsetY * dstBytesWidth;
+ // Add horizontal offset
+ dst += offsetX * 4;
+ for (int row = 0; row < numRows; row++)
+ {
+ ::memcpy(dst, src, numBytes);
+ src += srcBytesWidth;
+ dst += dstBytesWidth;
+ }
+ }
+ else
+ {
+ // Put original in lower right corner
+
+ // Add vertical offset
+ dst += (m_height - (srcHeight + offsetY)) * dstBytesWidth;
+ // Add horizontal offset
+ if (m_width > (srcWidth + offsetX)) {
+ dst += (m_width - (srcWidth + offsetX)) * 4;
+ }
+ else {
+ src += (srcWidth + offsetX - m_width) * 4;
+ }
+ for (int row = 0; row < numRows; row++) {
+ ::memcpy(dst, src, numBytes);
+ src += srcBytesWidth;
+ dst += dstBytesWidth;
+ }
+ }
+ }
+// doesn't compile under Linux delete [] tempData;
+ delete tempData;
+ }
+ else {
+ // Allocation failed, restore old data
+ m_data = tempData;
+ success = false;
+ }
+ }
+
+ return success;
+}
+
diff --git a/source/gameengine/GamePlayer/common/GPC_RawImage.h b/source/gameengine/GamePlayer/common/GPC_RawImage.h
new file mode 100644
index 00000000000..ff4c532dd4d
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_RawImage.h
@@ -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 *****
+ */
+
+#ifndef __GPC_RAWIMAGE_H__
+#define __GPC_RAWIMAGE_H__
+
+/**
+ * This memory resource reads images from the application resources.
+ * Images are expected to be stored as raw RGBA bytes.
+ * You can generate these images by exporting images with an alpha
+ * channel from Photoshop in RAW format with interleaved channels.
+ */
+
+class GPC_RawImage
+{
+public:
+ GPC_RawImage();
+
+ typedef enum {
+ alignTopLeft,
+ alignBottomRight
+ } TImageAlignment;
+
+ /**
+ * Loads the image form the resource into memory.
+ * Converts size of the image and places it with given alignment.
+ * @param hInstApp The application's instance (location of the resources).
+ * @param lpName Name of the resource.
+ * @param lpType Type of the resource.
+ * @param srcWidth The width of the resource image.
+ * @param srcHeight The height of the resource image.
+ * @param width The width of the image created.
+ * @param height The height of the image created.
+ * @param alignment How the resource image is located in the image created.
+ * @param offsetX Amount of horzontal offset applied to the resource image.
+ * @param offsetY Amount of vertical offset applied to the resource image.
+ */
+ virtual bool Load(char *srcName,
+ int destWidth, int destHeight,
+ TImageAlignment alignment = alignTopLeft,
+ int offsetX = 0, int offsetY = 0);
+
+ /**
+ * Returns the width of the image.
+ * @return The width of the image.
+ */
+ virtual int Width() const
+ {
+ return m_width;
+ }
+
+ /**
+ * Returns the height of the image.
+ * @return The height of the image.
+ */
+ virtual int Height() const
+ {
+ return m_height;
+ }
+
+ /**
+ * Returns a pointer to the data loaded from the resource.
+ * @return A pointer to the data loaded from the resource.
+ */
+ virtual unsigned char *Data() const
+ {
+ return m_data;
+ }
+
+ /**
+ * Returns the size of the data loaded from the resource.
+ * @return The size of the loaded from the resource.
+ */
+ virtual int DataSize() const
+ {
+ return m_dataSize;
+ }
+
+protected:
+ /**
+ * Disposes the data stored at the m_data member.
+ */
+// virtual void disposeData(void);
+
+protected:
+ unsigned char *m_data;
+ int m_dataSize;
+ int m_width;
+ int m_height;
+};
+
+#endif // __GPC_RAWIMAGE_H__
+
diff --git a/source/gameengine/GamePlayer/common/GPC_RawLoadDotBlendArray.cpp b/source/gameengine/GamePlayer/common/GPC_RawLoadDotBlendArray.cpp
new file mode 100644
index 00000000000..2ccd98b368a
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_RawLoadDotBlendArray.cpp
@@ -0,0 +1,9313 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 is automatically generated. Do not edit by hand!
+
+#include "GPC_RawLoadDotBlendArray.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void GetRawLoadingAnimation(unsigned char **data, int *dataSize)
+{
+ // create an array that will automatically be deleted when)
+ // we're outta this scope
+ static unsigned char load_blend[]= { 66, 76, 69, 78, 68, 70,
+ 73, 10, 0, 2, 21, 0, 0, 2, 22, 0, 0, 0, 0, 0, 0,
+ 2, 30, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 65, 25, 242, 2, 0, 2, 29, 253, 0, 0, 0, 4, 160, 249, 227,
+ 5, 65, 25, 242, 2, 0, 2, 29, 237, 0, 0, 0, 10, 39, 161,
+ 89, 128, 65, 248, 18, 0, 0, 2, 28, 205, 179, 76, 248, 13, 9,
+ 10, 156, 188, 58, 101, 43, 138, 63, 142, 132, 111, 231, 106, 44, 72,
+ 171, 116, 148, 204, 204, 104, 121, 88, 224, 36, 141, 195, 251, 160, 141,
+ 162, 12, 177, 93, 203, 236, 68, 235, 2, 137, 27, 34, 49, 52, 25,
+ 83, 60, 100, 208, 12, 234, 185, 206, 97, 0, 109, 170, 238, 253, 66,
+ 0, 68, 0, 0, 236, 253, 127, 0, 246, 18, 0, 82, 0, 0, 0,
+ 42, 247, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0,
+ 0, 0, 0, 0, 0, 36, 0, 2, 0, 0, 236, 253, 127, 0, 224,
+ 253, 127, 0, 224, 253, 127, 72, 249, 18, 0, 219, 128, 251, 119, 104,
+ 78, 249, 119, 255, 255, 255, 255, 0, 0, 0, 64, 111, 122, 152, 187,
+ 158, 149, 34, 236, 158, 103, 110, 35, 246, 67, 137, 177, 29, 56, 22,
+ 101, 64, 134, 124, 38, 155, 203, 128, 162, 3, 184, 27, 114, 80, 94,
+ 145, 136, 82, 121, 92, 7, 241, 119, 134, 12, 246, 193, 229, 95, 180,
+ 47, 135, 212, 231, 14, 59, 120, 218, 79, 151, 205, 221, 116, 27, 122,
+ 92, 0, 68, 0, 111, 0, 99, 0, 117, 0, 109, 0, 101, 0, 110,
+ 0, 116, 0, 115, 0, 82, 145, 252, 119, 255, 255, 255, 255, 60, 247,
+ 18, 0, 0, 0, 0, 0, 92, 247, 18, 0, 0, 16, 0, 0, 4,
+ 0, 0, 0, 0, 0, 242, 2, 0, 0, 242, 2, 32, 110, 172, 7,
+ 3, 239, 0, 0, 0, 0, 162, 7, 0, 0, 0, 64, 149, 244, 255,
+ 174, 70, 126, 180, 169, 78, 97, 78, 32, 67, 111, 110, 116, 101, 110,
+ 116, 32, 84, 101, 97, 109, 0, 247, 18, 0, 0, 16, 0, 0, 4,
+ 0, 0, 0, 0, 0, 242, 2, 0, 0, 242, 2, 80, 33, 90, 7,
+ 2, 32, 0, 0, 0, 0, 72, 7, 82, 145, 252, 119, 255, 255, 255,
+ 255, 168, 247, 18, 0, 0, 0, 0, 0, 200, 247, 18, 0, 0, 16,
+ 0, 0, 4, 0, 0, 0, 0, 0, 242, 2, 0, 0, 242, 2, 64,
+ 33, 88, 7, 2, 67, 0, 0, 0, 0, 72, 7, 216, 69, 0, 2,
+ 99, 111, 110, 116, 101, 110, 116, 99, 114, 101, 97, 116, 105, 111, 110,
+ 64, 98, 108, 101, 110, 100, 101, 114, 46, 110, 108, 0, 2, 81, 67,
+ 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 216, 69, 0, 0, 0,
+ 0, 72, 7, 116, 249, 18, 0, 127, 164, 252, 119, 0, 0, 242, 2,
+ 103, 154, 252, 119, 0, 0, 0, 0, 128, 26, 2, 0, 112, 112, 247,
+ 2, 12, 155, 252, 119, 255, 255, 255, 255, 40, 248, 18, 0, 0, 0,
+ 0, 0, 124, 249, 18, 0, 0, 16, 0, 0, 0, 236, 179, 7, 120,
+ 1, 242, 2, 48, 62, 8, 0, 184, 250, 18, 0, 0, 0, 72, 7,
+ 0, 112, 166, 7, 0, 0, 242, 2, 80, 0, 242, 2, 80, 0, 242,
+ 2, 0, 0, 226, 7, 0, 16, 162, 7, 0, 240, 5, 0, 248, 3,
+ 242, 2, 248, 3, 242, 2, 10, 0, 0, 0, 1, 0, 0, 0, 248,
+ 3, 242, 2, 120, 1, 242, 2, 112, 236, 179, 7, 120, 1, 242, 2,
+ 120, 1, 242, 2, 104, 236, 179, 7, 0, 16, 0, 0, 4, 0, 0,
+ 0, 0, 0, 242, 2, 0, 0, 242, 2, 64, 0, 162, 7, 3, 239,
+ 0, 0, 0, 0, 162, 7, 112, 236, 179, 7, 96, 157, 12, 3, 112,
+ 236, 179, 7, 120, 1, 242, 2, 104, 236, 179, 7, 18, 0, 0, 0,
+ 168, 248, 18, 0, 166, 166, 252, 119, 0, 0, 72, 7, 0, 48, 84,
+ 7, 64, 27, 84, 7, 0, 0, 242, 2, 236, 248, 18, 0, 176, 160,
+ 252, 119, 0, 0, 72, 7, 0, 32, 84, 7, 0, 16, 0, 0, 0,
+ 0, 242, 2, 64, 27, 84, 7, 1, 0, 0, 0, 136, 4, 0, 0,
+ 0, 27, 84, 7, 144, 1, 161, 7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 145, 0, 0, 0, 145, 0, 0, 0, 152, 0, 0, 0, 0, 0,
+ 72, 7, 144, 249, 18, 0, 9, 151, 252, 119, 0, 32, 84, 7, 0,
+ 16, 0, 0, 143, 157, 252, 119, 86, 250, 18, 0, 72, 27, 84, 7,
+ 32, 0, 226, 7, 8, 0, 0, 0, 193, 0, 0, 0, 25, 0, 0,
+ 0, 0, 0, 242, 2, 135, 2, 0, 0, 112, 236, 179, 7, 64, 33,
+ 88, 7, 19, 0, 0, 0, 0, 249, 18, 0, 0, 67, 0, 0, 72,
+ 27, 84, 7, 0, 0, 0, 0, 0, 0, 0, 0, 200, 59, 90, 7,
+ 0, 0, 0, 0, 63, 0, 0, 0, 72, 33, 88, 7, 128, 26, 2,
+ 0, 112, 112, 247, 2, 0, 0, 0, 0, 16, 0, 0, 0, 224, 249,
+ 18, 0, 255, 255, 223, 255, 32, 0, 0, 0, 252, 24, 242, 2, 144,
+ 0, 0, 0, 8, 0, 0, 0, 77, 26, 2, 0, 1, 120, 64, 0,
+ 80, 6, 242, 2, 109, 26, 228, 7, 210, 119, 64, 0, 16, 0, 0,
+ 0, 191, 119, 64, 0, 65, 97, 108, 46, 0, 2, 26, 101, 0, 0,
+ 0, 6, 77, 194, 164, 27, 66, 114, 105, 0, 0, 2, 26, 77, 0,
+ 7, 126, 76, 0, 0, 0, 1, 121, 216, 88, 60, 9, 46, 197, 144,
+ 120, 249, 120, 38, 9, 47, 236, 125, 7, 120, 19, 71, 211, 240, 158,
+ 108, 176, 1, 3, 162, 155, 46, 211, 171, 113, 161, 186, 232, 132, 49,
+ 29, 131, 232, 132, 18, 100, 192, 96, 83, 140, 177, 77, 77, 192, 162,
+ 147, 64, 192, 9, 189, 37, 14, 16, 8, 9, 197, 96, 211, 193, 18,
+ 37, 116, 136, 147, 80, 2, 164, 152, 150, 0, 129, 196, 132, 22, 170,
+ 254, 153, 211, 173, 180, 42, 167, 147, 49, 223, 251, 230, 251, 126, 204,
+ 115, 104, 110, 119, 102, 118, 118, 119, 118, 102, 118, 111, 116, 106, 25,
+ 61, 210, 159, 120, 77, 9, 35, 132, 40, 178, 238, 111, 237, 30, 209,
+ 169, 117, 231, 200, 214, 221, 6, 142, 11, 10, 10, 234, 6, 160, 10,
+ 42, 110, 60, 43, 73, 240, 143, 131, 43, 24, 174, 182, 112, 141, 138,
+ 142, 139, 39, 78, 254, 186, 119, 35, 100, 8, 124, 166, 206, 138, 247,
+ 106, 43, 210, 56, 226, 36, 13, 78, 140, 137, 113, 160, 167, 184, 26,
+ 160, 205, 158, 22, 239, 165, 135, 43, 125, 85, 188, 87, 218, 202, 120,
+ 47, 213, 23, 112, 191, 35, 222, 139, 16, 147, 39, 92, 30, 164, 0,
+ 241, 84, 136, 20, 28, 241, 38, 145, 45, 123, 180, 44, 45, 210, 182,
+ 19, 121, 229, 206, 68, 124, 219, 63, 138, 135, 117, 20, 47, 13, 96,
+ 164, 19, 81, 60, 89, 188, 52, 6, 79, 11, 176, 133, 103, 1, 91,
+ 60, 45, 131, 71, 0, 78, 179, 226, 217, 180, 75, 24, 188, 244, 25,
+ 241, 94, 90, 171, 140, 28, 139, 135, 117, 20, 79, 7, 48, 177, 242,
+ 179, 193, 211, 49, 120, 74, 128, 145, 206, 204, 238, 150, 7, 139, 167,
+ 100, 240, 140, 211, 227, 189, 116, 20, 175, 128, 45, 30, 214, 81, 188,
+ 4, 128, 149, 34, 158, 81, 97, 219, 110, 2, 131, 167, 2, 24, 233,
+ 204, 120, 182, 252, 84, 12, 30, 206, 105, 130, 5, 175, 143, 13, 30,
+ 214, 181, 99, 116, 64, 53, 157, 202, 103, 197, 243, 133, 79, 212, 137,
+ 246, 34, 94, 192, 52, 51, 78, 154, 56, 47, 28, 51, 199, 190, 98,
+ 61, 197, 205, 153, 106, 214, 39, 173, 56, 215, 246, 184, 88, 79, 113,
+ 83, 1, 22, 120, 75, 224, 166, 50, 184, 26, 128, 145, 150, 206, 165,
+ 61, 174, 134, 193, 205, 213, 199, 123, 165, 138, 184, 132, 209, 77, 138,
+ 139, 245, 20, 55, 13, 96, 164, 197, 121, 114, 214, 183, 52, 6, 87,
+ 11, 48, 210, 226, 92, 165, 57, 193, 213, 50, 184, 217, 159, 1, 142,
+ 136, 107, 209, 1, 6, 23, 235, 41, 174, 30, 96, 164, 21, 230, 214,
+ 137, 188, 122, 6, 55, 0, 96, 164, 69, 220, 116, 39, 124, 3, 24,
+ 220, 156, 79, 97, 46, 62, 51, 235, 130, 51, 25, 176, 222, 50, 23,
+ 0, 7, 136, 184, 74, 39, 184, 169, 12, 174, 6, 96, 164, 77, 96,
+ 244, 209, 102, 46, 24, 220, 220, 213, 48, 23, 159, 138, 237, 59, 25,
+ 51, 172, 183, 204, 5, 192, 72, 171, 146, 224, 155, 198, 224, 106, 1,
+ 70, 90, 196, 77, 112, 130, 171, 101, 112, 9, 192, 72, 139, 186, 143,
+ 125, 179, 151, 129, 48, 184, 104, 7, 181, 34, 110, 186, 19, 92, 172,
+ 111, 207, 218, 91, 17, 87, 101, 39, 195, 79, 40, 47, 216, 211, 14,
+ 212, 22, 44, 55, 215, 11, 246, 111, 166, 85, 143, 177, 44, 231, 202,
+ 99, 133, 112, 253, 104, 190, 200, 155, 248, 19, 237, 225, 75, 230, 254,
+ 182, 221, 189, 96, 189, 4, 67, 92, 128, 40, 136, 167, 39, 87, 224,
+ 54, 241, 128, 127, 21, 61, 204, 190, 5, 255, 18, 230, 69, 146, 180,
+ 211, 17, 36, 189, 113, 71, 98, 92, 25, 41, 92, 217, 43, 160, 207,
+ 112, 41, 253, 158, 40, 148, 31, 63, 81, 96, 127, 211, 80, 167, 161,
+ 76, 99, 231, 139, 60, 89, 153, 114, 62, 139, 52, 3, 67, 90, 225,
+ 255, 133, 78, 173, 141, 28, 58, 180, 230, 65, 122, 159, 183, 63, 61,
+ 208, 212, 137, 32, 228, 56, 240, 188, 138, 244, 252, 213, 73, 153, 60,
+ 182, 206, 9, 158, 170, 56, 20, 121, 19, 205, 153, 120, 47, 147, 201,
+ 158, 118, 9, 71, 231, 8, 231, 133, 206, 145, 102, 169, 217, 7, 82,
+ 91, 128, 107, 156, 174, 133, 156, 243, 48, 55, 231, 223, 208, 220, 48,
+ 115, 240, 135, 7, 51, 72, 226, 189, 201, 131, 153, 35, 79, 243, 85,
+ 80, 144, 209, 203, 139, 43, 128, 189, 243, 224, 54, 42, 172, 115, 36,
+ 216, 102, 152, 163, 236, 79, 204, 195, 155, 0, 115, 164, 93, 6, 250,
+ 5, 87, 118, 201, 103, 10, 188, 176, 191, 26, 232, 36, 150, 69, 216,
+ 205, 81, 1, 6, 46, 139, 113, 67, 203, 94, 173, 85, 61, 90, 118,
+ 107, 219, 210, 86, 220, 193, 33, 253, 35, 71, 15, 30, 59, 42, 38,
+ 62, 57, 73, 21, 29, 63, 68, 213, 61, 38, 57, 57, 46, 126, 88,
+ 82, 255, 68, 184, 139, 30, 57, 178, 127, 100, 76, 210, 136, 228, 209,
+ 9, 253, 7, 38, 140, 29, 52, 50, 46, 41, 54, 38, 177, 97, 66,
+ 98, 204, 200, 209, 209, 67, 98, 18, 251, 147, 255, 109, 127, 133, 48,
+ 88, 131, 43, 150, 176, 211, 110, 213, 38, 170, 67, 168, 55, 22, 29,
+ 74, 5, 219, 181, 220, 188, 198, 81, 143, 88, 27, 153, 243, 61, 232,
+ 16, 92, 185, 103, 30, 43, 30, 194, 181, 58, 180, 132, 198, 190, 205,
+ 242, 166, 162, 14, 101, 43, 90, 234, 13, 160, 239, 6, 122, 223, 142,
+ 139, 202, 162, 240, 1, 16, 205, 3, 26, 190, 233, 97, 123, 95, 142,
+ 179, 222, 251, 138, 245, 94, 176, 30, 64, 123, 184, 44, 197, 89, 5,
+ 106, 209, 82, 70, 135, 210, 39, 152, 215, 121, 218, 216, 86, 196, 8,
+ 48, 94, 250, 197, 96, 167, 182, 64, 63, 114, 31, 40, 240, 194, 254,
+ 206, 3, 94, 88, 30, 78, 237, 240, 34, 115, 223, 204, 205, 233, 121,
+ 39, 235, 212, 85, 153, 30, 175, 139, 133, 159, 25, 205, 101, 121, 166,
+ 23, 254, 128, 94, 131, 101, 175, 59, 158, 15, 170, 61, 212, 32, 143,
+ 157, 159, 93, 85, 219, 227, 54, 56, 242, 155, 67, 153, 177, 74, 165,
+ 67, 158, 23, 63, 51, 210, 251, 195, 241, 190, 17, 185, 117, 210, 52,
+ 246, 114, 125, 81, 106, 155, 70, 33, 174, 47, 142, 185, 170, 192, 60,
+ 16, 226, 19, 129, 248, 103, 78, 159, 134, 161, 124, 214, 170, 125, 211,
+ 118, 124, 159, 210, 133, 52, 179, 222, 25, 8, 124, 141, 141, 115, 158,
+ 24, 194, 219, 69, 157, 228, 209, 126, 13, 228, 134, 113, 120, 61, 48,
+ 157, 86, 60, 55, 157, 19, 148, 177, 52, 211, 142, 106, 177, 121, 14,
+ 112, 126, 106, 136, 247, 97, 18, 123, 2, 176, 20, 116, 60, 248, 246,
+ 138, 213, 150, 88, 51, 77, 156, 75, 106, 191, 181, 31, 67, 236, 0,
+ 124, 164, 236, 247, 212, 217, 51, 91, 133, 188, 120, 63, 114, 205, 179,
+ 174, 135, 59, 191, 188, 252, 198, 237, 183, 66, 88, 103, 10, 187, 21,
+ 103, 107, 191, 179, 21, 102, 57, 223, 161, 190, 27, 116, 21, 251, 80,
+ 24, 109, 88, 235, 78, 173, 91, 245, 80, 181, 143, 106, 217, 182, 181,
+ 61, 117, 57, 17, 255, 20, 215, 29, 56, 212, 113, 42, 157, 55, 252,
+ 171, 66, 62, 81, 212, 130, 207, 108, 248, 204, 129, 207, 199, 240, 57,
+ 11, 40, 94, 1, 77, 49, 143, 79, 20, 175, 160, 172, 152, 71, 37,
+ 82, 139, 236, 80, 108, 82, 148, 129, 242, 101, 138, 115, 92, 25, 146,
+ 24, 61, 104, 80, 92, 114, 191, 192, 1, 254, 201, 195, 162, 255, 11,
+ 118, 171, 149, 172, 157, 142, 154, 168, 178, 96, 56, 55, 214, 137, 49,
+ 73, 49, 209, 137, 131, 99, 95, 199, 106, 255, 255, 222, 127, 171, 167,
+ 48, 107, 174, 73, 252, 115, 151, 46, 231, 241, 99, 133, 242, 122, 7,
+ 66, 125, 54, 234, 53, 235, 179, 81, 231, 89, 159, 221, 144, 250, 236,
+ 54, 237, 59, 181, 38, 221, 222, 177, 153, 139, 16, 9, 103, 156, 135,
+ 177, 32, 20, 242, 31, 52, 50, 38, 126, 72, 255, 30, 49, 19, 146,
+ 251, 147, 193, 201, 253, 253, 253, 243, 237, 212, 19, 7, 37, 155, 121,
+ 55, 28, 26, 23, 31, 61, 210, 220, 66, 62, 248, 121, 139, 159, 211,
+ 37, 34, 28, 139, 207, 78, 181, 250, 108, 60, 243, 64, 31, 142, 126,
+ 26, 227, 120, 26, 251, 11, 182, 254, 212, 99, 5, 94, 169, 39, 204,
+ 215, 244, 65, 213, 29, 252, 193, 149, 203, 39, 194, 237, 203, 70, 151,
+ 244, 216, 199, 250, 56, 243, 165, 231, 15, 139, 14, 1, 125, 116, 79,
+ 240, 201, 236, 61, 250, 108, 122, 239, 43, 214, 23, 34, 133, 65, 198,
+ 130, 5, 213, 10, 181, 2, 99, 243, 170, 30, 142, 113, 95, 234, 229,
+ 246, 2, 172, 252, 50, 146, 228, 108, 134, 125, 220, 122, 216, 115, 173,
+ 123, 162, 192, 11, 251, 187, 10, 117, 10, 202, 35, 169, 109, 223, 108,
+ 238, 91, 65, 7, 123, 76, 63, 171, 100, 17, 253, 120, 176, 197, 15,
+ 15, 16, 141, 51, 255, 235, 248, 167, 86, 216, 126, 186, 250, 11, 200,
+ 137, 197, 246, 45, 126, 25, 73, 110, 153, 238, 155, 80, 58, 148, 183,
+ 143, 40, 99, 107, 122, 46, 179, 9, 246, 155, 112, 95, 136, 234, 255,
+ 72, 115, 28, 94, 195, 66, 13, 222, 20, 46, 244, 165, 56, 211, 37,
+ 224, 234, 6, 87, 15, 113, 230, 75, 136, 88, 219, 57, 199, 51, 170,
+ 253, 34, 127, 158, 238, 65, 191, 2, 31, 2, 109, 217, 118, 163, 116,
+ 4, 240, 62, 112, 230, 244, 60, 158, 222, 3, 166, 145, 250, 82, 37,
+ 213, 101, 206, 220, 214, 100, 177, 29, 37, 177, 222, 151, 16, 235, 11,
+ 95, 172, 30, 134, 23, 209, 13, 111, 67, 200, 164, 72, 54, 214, 116,
+ 246, 167, 187, 19, 239, 229, 107, 185, 235, 18, 225, 112, 208, 198, 200,
+ 70, 227, 51, 236, 3, 141, 207, 2, 54, 66, 252, 182, 201, 188, 143,
+ 29, 245, 21, 207, 115, 85, 234, 31, 152, 244, 110, 93, 161, 31, 21,
+ 51, 235, 242, 95, 230, 244, 9, 111, 22, 192, 11, 177, 144, 222, 231,
+ 189, 125, 199, 134, 167, 240, 75, 126, 255, 64, 208, 231, 175, 30, 53,
+ 81, 199, 214, 62, 23, 94, 179, 227, 68, 53, 234, 238, 72, 160, 71,
+ 154, 239, 139, 188, 39, 232, 246, 163, 202, 245, 15, 108, 6, 250, 163,
+ 64, 131, 247, 200, 183, 41, 240, 90, 38, 210, 31, 27, 176, 40, 235,
+ 210, 225, 209, 225, 115, 47, 61, 56, 128, 244, 31, 172, 127, 24, 126,
+ 233, 238, 172, 125, 101, 70, 111, 222, 139, 245, 143, 87, 255, 24, 126,
+ 134, 251, 58, 244, 234, 209, 195, 33, 120, 255, 113, 11, 213, 222, 160,
+ 152, 19, 225, 57, 77, 139, 238, 193, 251, 171, 17, 183, 194, 180, 237,
+ 106, 135, 125, 219, 198, 180, 7, 233, 115, 107, 47, 209, 68, 62, 152,
+ 161, 169, 179, 249, 8, 78, 27, 25, 224, 121, 41, 107, 199, 172, 66,
+ 252, 139, 199, 126, 194, 78, 37, 98, 232, 23, 135, 75, 239, 216, 219,
+ 170, 222, 166, 130, 135, 216, 246, 231, 137, 237, 247, 122, 233, 207, 63,
+ 233, 85, 221, 208, 177, 233, 196, 172, 115, 15, 167, 103, 125, 49, 255,
+ 184, 134, 106, 16, 27, 159, 153, 255, 204, 241, 153, 48, 87, 16, 159,
+ 1, 47, 245, 149, 195, 163, 15, 64, 95, 108, 214, 58, 198, 103, 126,
+ 220, 82, 14, 47, 155, 89, 113, 50, 151, 212, 158, 227, 156, 80, 123,
+ 142, 107, 21, 231, 139, 181, 231, 133, 109, 236, 185, 157, 189, 12, 249,
+ 119, 111, 174, 44, 246, 60, 32, 40, 223, 182, 156, 181, 231, 174, 246,
+ 96, 24, 7, 226, 56, 190, 195, 204, 31, 142, 49, 142, 99, 183, 214,
+ 218, 78, 45, 91, 181, 118, 26, 8, 122, 137, 248, 213, 185, 193, 240,
+ 81, 149, 169, 41, 98, 23, 7, 190, 226, 204, 113, 224, 43, 206, 28,
+ 7, 190, 226, 254, 230, 204, 113, 96, 83, 197, 43, 14, 227, 192, 166,
+ 10, 140, 3, 253, 132, 248, 239, 21, 241, 84, 188, 32, 52, 14, 12,
+ 246, 31, 158, 48, 204, 226, 66, 251, 39, 131, 243, 28, 155, 24, 211,
+ 31, 43, 243, 24, 168, 228, 121, 46, 36, 116, 133, 138, 64, 250, 19,
+ 27, 246, 46, 113, 95, 59, 14, 252, 87, 247, 223, 230, 239, 77, 247,
+ 63, 191, 113, 96, 238, 163, 199, 138, 156, 180, 54, 150, 152, 5, 227,
+ 148, 14, 236, 243, 155, 84, 235, 249, 39, 158, 83, 101, 139, 231, 244,
+ 169, 71, 33, 86, 193, 235, 176, 249, 122, 83, 49, 75, 63, 15, 243,
+ 57, 2, 123, 63, 154, 185, 79, 16, 235, 139, 128, 55, 134, 29, 28,
+ 68, 44, 227, 132, 243, 196, 43, 156, 227, 121, 162, 242, 120, 123, 146,
+ 134, 48, 92, 1, 235, 32, 254, 74, 131, 190, 116, 125, 166, 80, 142,
+ 249, 71, 65, 253, 50, 150, 83, 191, 156, 176, 214, 220, 55, 91, 191,
+ 60, 223, 206, 47, 207, 119, 234, 151, 199, 137, 126, 248, 165, 157, 95,
+ 126, 41, 250, 101, 172, 151, 243, 203, 218, 162, 175, 20, 246, 118, 31,
+ 253, 242, 159, 146, 126, 121, 190, 173, 95, 22, 251, 48, 155, 238, 85,
+ 63, 135, 56, 13, 250, 231, 35, 198, 46, 230, 179, 3, 218, 46, 126,
+ 98, 63, 166, 69, 152, 239, 239, 70, 248, 43, 172, 177, 213, 56, 113,
+ 114, 26, 42, 172, 253, 161, 247, 180, 63, 214, 63, 228, 53, 41, 210,
+ 124, 206, 160, 106, 89, 88, 12, 185, 18, 166, 91, 207, 50, 105, 220,
+ 128, 50, 209, 184, 1, 231, 3, 229, 125, 27, 55, 252, 123, 226, 6,
+ 156, 19, 118, 31, 136, 243, 245, 54, 110, 120, 189, 184, 161, 59, 236,
+ 114, 230, 128, 173, 210, 237, 143, 247, 10, 165, 207, 225, 118, 216, 62,
+ 199, 238, 222, 42, 208, 41, 111, 58, 254, 186, 109, 241, 94, 250, 94,
+ 214, 117, 164, 4, 94, 154, 61, 86, 30, 67, 253, 2, 3, 99, 253,
+ 182, 165, 195, 231, 1, 206, 215, 25, 159, 96, 210, 22, 44, 227, 16,
+ 219, 115, 77, 187, 253, 150, 94, 145, 195, 133, 1, 206, 71, 68, 195,
+ 105, 56, 78, 60, 31, 3, 55, 146, 178, 124, 249, 30, 126, 197, 242,
+ 229, 203, 79, 159, 190, 235, 100, 143, 102, 110, 112, 32, 88, 135, 2,
+ 226, 136, 148, 23, 85, 207, 254, 172, 181, 81, 163, 127, 247, 57, 124,
+ 163, 70, 137, 160, 16, 49, 137, 141, 254, 181, 242, 145, 234, 228, 237,
+ 223, 27, 251, 67, 123, 87, 73, 92, 79, 45, 232, 243, 211, 125, 226,
+ 186, 82, 90, 215, 159, 222, 167, 187, 66, 119, 57, 222, 139, 226, 35,
+ 14, 197, 79, 0, 24, 233, 17, 95, 97, 193, 223, 173, 208, 252, 108,
+ 197, 79, 96, 240, 85, 0, 11, 109, 0, 190, 135, 5, 127, 191, 34,
+ 221, 104, 197, 87, 49, 248, 217, 123, 193, 63, 138, 248, 158, 22, 252,
+ 158, 16, 111, 89, 241, 17, 135, 226, 235, 1, 70, 122, 142, 57, 141,
+ 42, 170, 240, 228, 52, 247, 172, 248, 122, 6, 63, 0, 96, 164, 71,
+ 67, 70, 207, 105, 52, 10, 13, 135, 231, 1, 20, 63, 128, 193, 207,
+ 1, 187, 131, 244, 40, 15, 53, 64, 248, 204, 32, 224, 132, 21, 31,
+ 113, 40, 126, 42, 192, 1, 34, 62, 181, 149, 222, 138, 126, 156, 178,
+ 123, 172, 5, 63, 149, 193, 71, 187, 134, 244, 28, 19, 19, 233, 125,
+ 98, 56, 180, 129, 20, 95, 195, 224, 19, 145, 30, 249, 23, 102, 248,
+ 231, 148, 136, 245, 162, 182, 23, 237, 109, 40, 107, 79, 247, 91, 109,
+ 103, 247, 86, 66, 230, 147, 127, 64, 64, 160, 243, 220, 165, 51, 182,
+ 182, 55, 0, 120, 105, 50, 65, 198, 76, 199, 92, 36, 142, 188, 181,
+ 189, 111, 109, 239, 219, 191, 188, 216, 94, 92, 79, 22, 219, 146, 105,
+ 125, 198, 75, 215, 82, 57, 197, 66, 69, 234, 119, 140, 109, 201, 100,
+ 108, 11, 192, 72, 207, 49, 49, 178, 222, 103, 132, 2, 215, 172, 197,
+ 182, 48, 248, 116, 221, 34, 236, 97, 225, 223, 90, 65, 90, 91, 109,
+ 145, 38, 211, 206, 182, 136, 248, 212, 246, 126, 194, 45, 84, 232, 47,
+ 198, 123, 117, 129, 0, 121, 147, 194, 28, 155, 53, 165, 252, 207, 216,
+ 218, 132, 46, 17, 173, 162, 71, 197, 36, 70, 75, 217, 137, 34, 121,
+ 28, 51, 180, 177, 194, 30, 113, 241, 35, 135, 211, 111, 109, 110, 172,
+ 151, 187, 124, 30, 6, 220, 210, 196, 237, 95, 123, 240, 224, 225, 230,
+ 54, 153, 23, 35, 63, 159, 158, 217, 39, 246, 87, 99, 189, 161, 107,
+ 53, 10, 176, 29, 96, 126, 28, 158, 149, 167, 248, 46, 225, 39, 118,
+ 186, 159, 113, 118, 255, 11, 181, 252, 51, 116, 235, 253, 207, 77, 2,
+ 249, 199, 134, 230, 252, 244, 51, 235, 49, 229, 148, 108, 136, 92, 144,
+ 245, 219, 136, 15, 212, 117, 158, 142, 16, 112, 60, 58, 213, 227, 111,
+ 247, 169, 110, 232, 48, 243, 168, 192, 87, 245, 67, 64, 75, 242, 229,
+ 188, 131, 135, 4, 25, 245, 188, 98, 89, 18, 191, 54, 121, 181, 58,
+ 113, 231, 178, 12, 172, 7, 56, 11, 203, 174, 133, 148, 204, 20, 198,
+ 122, 102, 209, 224, 133, 173, 190, 13, 166, 109, 30, 139, 45, 100, 220,
+ 190, 232, 156, 166, 193, 208, 181, 70, 231, 207, 246, 243, 246, 103, 181,
+ 237, 5, 184, 46, 17, 70, 111, 171, 158, 14, 97, 250, 170, 231, 11,
+ 214, 29, 194, 139, 207, 219, 133, 126, 152, 239, 237, 207, 19, 254, 211,
+ 127, 212, 23, 88, 199, 129, 234, 47, 234, 44, 213, 95, 212, 47, 212,
+ 103, 123, 253, 181, 119, 142, 175, 171, 191, 174, 254, 140, 105, 238, 235,
+ 47, 253, 51, 231, 99, 184, 223, 103, 182, 82, 154, 70, 234, 62, 127,
+ 57, 35, 175, 75, 47, 93, 246, 154, 250, 27, 105, 214, 95, 47, 9,
+ 253, 45, 124, 177, 122, 56, 171, 191, 230, 243, 28, 187, 252, 58, 251,
+ 231, 200, 233, 96, 87, 225, 50, 158, 54, 95, 90, 241, 202, 151, 190,
+ 106, 92, 207, 37, 218, 235, 78, 98, 219, 49, 78, 98, 47, 142, 249,
+ 63, 41, 38, 62, 105, 116, 162, 235, 22, 211, 210, 109, 229, 69, 254,
+ 158, 76, 185, 176, 55, 56, 109, 246, 43, 90, 17, 142, 117, 26, 243,
+ 217, 158, 210, 12, 30, 29, 159, 44, 215, 91, 157, 68, 219, 58, 166,
+ 109, 173, 216, 118, 152, 8, 143, 115, 210, 118, 17, 40, 193, 53, 25,
+ 61, 216, 117, 147, 202, 211, 214, 60, 30, 165, 120, 63, 74, 228, 231,
+ 105, 23, 35, 83, 59, 129, 182, 129, 218, 9, 220, 123, 176, 190, 174,
+ 75, 196, 96, 193, 78, 116, 27, 157, 76, 98, 163, 135, 140, 30, 79,
+ 70, 70, 199, 199, 88, 229, 227, 94, 83, 11, 178, 251, 59, 230, 65,
+ 42, 35, 221, 183, 19, 172, 63, 99, 203, 251, 4, 55, 108, 172, 251,
+ 252, 165, 225, 210, 55, 51, 121, 41, 59, 129, 190, 4, 124, 74, 198,
+ 235, 218, 9, 244, 71, 248, 217, 169, 78, 204, 6, 44, 51, 251, 38,
+ 161, 60, 3, 224, 12, 138, 103, 43, 163, 158, 143, 243, 91, 19, 28,
+ 235, 183, 38, 195, 202, 83, 207, 31, 111, 182, 37, 56, 78, 40, 35,
+ 36, 113, 122, 51, 161, 110, 56, 224, 225, 125, 244, 231, 47, 249, 31,
+ 191, 153, 105, 88, 221, 230, 187, 204, 55, 97, 39, 44, 135, 217, 145,
+ 156, 194, 153, 159, 107, 158, 185, 228, 132, 75, 59, 225, 196, 209, 25,
+ 143, 131, 93, 128, 75, 35, 94, 250, 99, 230, 43, 251, 168, 249, 250,
+ 159, 182, 19, 26, 81, 134, 190, 118, 186, 152, 28, 55, 42, 70, 24,
+ 211, 209, 9, 78, 185, 23, 176, 201, 88, 37, 228, 238, 113, 235, 186,
+ 65, 219, 131, 125, 121, 19, 182, 135, 28, 119, 190, 254, 105, 185, 16,
+ 215, 30, 179, 218, 30, 132, 223, 148, 237, 209, 28, 115, 222, 54, 45,
+ 23, 206, 32, 142, 90, 109, 15, 194, 227, 156, 246, 153, 19, 202, 228,
+ 108, 79, 194, 81, 235, 24, 6, 136, 247, 9, 22, 126, 5, 225, 243,
+ 132, 101, 94, 228, 254, 168, 109, 66, 123, 68, 109, 19, 158, 163, 208,
+ 56, 217, 140, 211, 41, 122, 84, 130, 195, 246, 222, 34, 127, 225, 215,
+ 212, 188, 4, 226, 104, 155, 178, 179, 221, 183, 77, 213, 71, 8, 71,
+ 236, 228, 138, 218, 43, 194, 133, 126, 107, 172, 151, 237, 223, 229, 226,
+ 237, 249, 188, 218, 166, 135, 158, 77, 4, 62, 15, 60, 155, 24, 109,
+ 219, 48, 255, 61, 16, 235, 41, 158, 173, 140, 249, 143, 97, 128, 191,
+ 90, 108, 135, 217, 59, 232, 45, 240, 223, 158, 77, 178, 216, 250, 232,
+ 105, 207, 240, 57, 142, 126, 228, 96, 254, 160, 192, 83, 201, 198, 48,
+ 172, 198, 187, 105, 155, 254, 211, 49, 183, 198, 189, 24, 28, 117, 214,
+ 178, 135, 252, 57, 222, 11, 245, 217, 65, 127, 131, 254, 93, 250, 11,
+ 253, 104, 138, 250, 241, 58, 250, 251, 208, 115, 199, 6, 212, 223, 203,
+ 197, 79, 240, 121, 209, 223, 25, 237, 99, 26, 163, 110, 90, 245, 87,
+ 111, 4, 95, 217, 152, 35, 250, 47, 241, 110, 26, 212, 163, 14, 83,
+ 253, 181, 149, 49, 255, 250, 11, 252, 97, 22, 244, 89, 230, 79, 179,
+ 158, 66, 251, 65, 84, 95, 5, 253, 109, 50, 106, 29, 171, 191, 170,
+ 191, 191, 108, 252, 127, 93, 127, 81, 103, 169, 254, 226, 57, 57, 234,
+ 179, 131, 254, 6, 255, 235, 236, 47, 62, 131, 109, 246, 58, 250, 91,
+ 109, 153, 234, 75, 179, 254, 182, 215, 228, 209, 254, 26, 103, 180, 191,
+ 217, 152, 234, 111, 156, 95, 181, 29, 168, 195, 189, 43, 95, 255, 146,
+ 218, 229, 105, 80, 207, 216, 95, 70, 198, 55, 98, 127, 179, 98, 253,
+ 170, 101, 60, 16, 237, 44, 200, 34, 232, 243, 116, 225, 147, 234, 239,
+ 61, 59, 253, 173, 211, 228, 255, 186, 254, 162, 206, 82, 253, 197, 179,
+ 61, 212, 103, 7, 253, 109, 252, 111, 179, 191, 154, 93, 168, 31, 175,
+ 163, 191, 165, 238, 124, 42, 232, 239, 245, 83, 75, 242, 164, 191, 69,
+ 166, 164, 239, 64, 29, 102, 236, 175, 166, 248, 242, 167, 59, 106, 30,
+ 208, 109, 20, 198, 2, 234, 177, 206, 106, 127, 89, 25, 243, 175, 191,
+ 208, 62, 238, 125, 212, 230, 79, 97, 189, 100, 21, 91, 254, 212, 162,
+ 207, 168, 191, 153, 125, 163, 215, 179, 250, 187, 69, 149, 186, 227, 255,
+ 186, 254, 162, 206, 90, 246, 230, 223, 197, 123, 161, 62, 91, 113, 180,
+ 184, 25, 119, 8, 32, 94, 119, 111, 142, 252, 241, 51, 189, 175, 163,
+ 254, 170, 90, 185, 175, 191, 251, 163, 106, 26, 157, 237, 205, 67, 151,
+ 253, 206, 31, 26, 30, 166, 153, 251, 233, 217, 64, 115, 110, 203, 155,
+ 59, 195, 91, 253, 209, 23, 161, 108, 205, 18, 239, 241, 181, 214, 246,
+ 226, 248, 221, 27, 75, 218, 12, 14, 150, 9, 243, 173, 226, 248, 195,
+ 32, 75, 212, 142, 206, 25, 206, 228, 168, 51, 233, 97, 45, 44, 11,
+ 168, 249, 113, 144, 179, 54, 71, 125, 62, 189, 49, 244, 81, 83, 207,
+ 114, 6, 157, 63, 122, 235, 25, 158, 243, 189, 249, 235, 156, 225, 105,
+ 192, 87, 227, 69, 46, 154, 47, 227, 121, 243, 149, 125, 206, 124, 253,
+ 39, 246, 230, 216, 190, 253, 222, 60, 33, 113, 244, 176, 196, 152, 164,
+ 36, 210, 173, 75, 219, 110, 173, 187, 119, 183, 223, 164, 43, 236, 78,
+ 212, 71, 26, 109, 247, 230, 216, 23, 251, 189, 121, 97, 225, 59, 14,
+ 156, 219, 123, 115, 205, 5, 24, 139, 11, 206, 247, 199, 180, 92, 56,
+ 23, 60, 111, 222, 31, 71, 138, 52, 67, 152, 118, 45, 253, 200, 199,
+ 115, 50, 173, 216, 134, 179, 61, 191, 135, 216, 31, 15, 55, 247, 252,
+ 26, 224, 163, 63, 239, 188, 79, 180, 92, 216, 243, 159, 51, 247, 201,
+ 83, 164, 25, 70, 207, 33, 71, 62, 86, 88, 206, 2, 206, 229, 243,
+ 44, 224, 156, 221, 89, 192, 57, 219, 179, 128, 188, 140, 159, 229, 44,
+ 224, 59, 102, 47, 117, 15, 250, 122, 209, 153, 45, 12, 126, 35, 182,
+ 208, 229, 179, 186, 150, 238, 219, 66, 214, 230, 73, 157, 95, 162, 77,
+ 162, 87, 222, 158, 251, 56, 191, 119, 198, 199, 85, 153, 173, 140, 255,
+ 162, 231, 113, 130, 45, 116, 244, 229, 249, 121, 158, 241, 95, 221, 75,
+ 221, 99, 246, 82, 119, 226, 189, 168, 191, 181, 209, 223, 160, 55, 171,
+ 191, 105, 203, 28, 159, 39, 235, 195, 229, 245, 87, 43, 202, 198, 230,
+ 31, 190, 206, 89, 150, 251, 190, 220, 158, 159, 251, 101, 182, 50, 254,
+ 139, 158, 199, 17, 231, 250, 75, 99, 81, 169, 231, 201, 158, 132, 227,
+ 200, 127, 237, 207, 185, 47, 247, 100, 116, 130, 179, 223, 99, 221, 177,
+ 234, 53, 230, 102, 161, 158, 91, 245, 58, 105, 68, 204, 200, 152, 228,
+ 209, 241, 206, 99, 212, 242, 175, 251, 252, 104, 145, 173, 94, 167, 105,
+ 99, 189, 84, 49, 238, 191, 91, 3, 159, 19, 105, 27, 249, 105, 204,
+ 207, 137, 24, 191, 101, 83, 238, 252, 249, 17, 158, 109, 37, 78, 111,
+ 22, 156, 215, 51, 174, 56, 225, 185, 142, 158, 55, 63, 231, 17, 238,
+ 51, 146, 129, 15, 251, 60, 8, 203, 226, 196, 231, 63, 125, 156, 202,
+ 98, 253, 91, 244, 109, 187, 218, 66, 140, 89, 104, 209, 54, 103, 109,
+ 142, 9, 110, 152, 9, 244, 70, 160, 55, 188, 145, 231, 71, 222, 249,
+ 124, 126, 228, 132, 101, 78, 54, 196, 5, 112, 229, 220, 6, 157, 185,
+ 21, 239, 149, 246, 27, 92, 55, 224, 186, 14, 215, 63, 255, 153, 24,
+ 21, 101, 160, 49, 42, 202, 130, 117, 227, 163, 71, 142, 16, 158, 85,
+ 36, 71, 39, 38, 11, 128, 109, 144, 106, 126, 126, 116, 220, 178, 63,
+ 247, 249, 206, 26, 239, 104, 68, 62, 108, 220, 139, 109, 196, 13, 129,
+ 133, 224, 200, 202, 41, 79, 164, 91, 149, 109, 27, 247, 226, 24, 209,
+ 184, 87, 119, 219, 126, 108, 204, 45, 13, 141, 75, 76, 74, 30, 154,
+ 24, 13, 173, 72, 70, 192, 1, 217, 206, 99, 68, 90, 46, 124, 135,
+ 245, 55, 115, 140, 216, 73, 108, 203, 18, 111, 223, 50, 207, 149, 167,
+ 101, 54, 205, 237, 226, 120, 13, 141, 139, 199, 175, 6, 136, 78, 218,
+ 182, 117, 61, 208, 169, 110, 59, 111, 151, 150, 11, 246, 227, 166, 185,
+ 221, 88, 145, 102, 160, 88, 78, 23, 182, 227, 188, 216, 245, 141, 96,
+ 180, 217, 180, 185, 148, 86, 52, 49, 35, 184, 140, 201, 59, 137, 253,
+ 100, 247, 24, 58, 177, 207, 236, 243, 63, 156, 79, 75, 159, 157, 140,
+ 182, 234, 119, 216, 99, 252, 46, 177, 199, 248, 157, 25, 235, 27, 214,
+ 62, 35, 141, 125, 159, 45, 122, 35, 21, 143, 202, 172, 132, 38, 1,
+ 238, 237, 67, 112, 206, 99, 153, 121, 176, 213, 45, 15, 203, 157, 91,
+ 121, 15, 191, 57, 246, 219, 135, 41, 23, 250, 13, 107, 60, 247, 42,
+ 236, 69, 175, 89, 159, 127, 98, 187, 84, 6, 213, 77, 179, 61, 176,
+ 202, 160, 176, 145, 33, 72, 46, 246, 185, 233, 40, 131, 55, 83, 46,
+ 60, 83, 52, 1, 124, 213, 218, 190, 138, 105, 31, 231, 37, 231, 166,
+ 115, 27, 132, 237, 7, 190, 230, 126, 15, 249, 178, 251, 61, 149, 216,
+ 134, 121, 191, 231, 109, 25, 233, 228, 241, 113, 201, 131, 99, 3, 73,
+ 108, 220, 224, 88, 212, 1, 123, 126, 74, 224, 163, 189, 225, 216, 71,
+ 21, 250, 234, 27, 204, 154, 122, 9, 122, 248, 10, 238, 225, 83, 245,
+ 34, 222, 75, 243, 60, 222, 75, 247, 12, 246, 79, 79, 205, 54, 150,
+ 234, 36, 242, 163, 123, 193, 156, 62, 214, 189, 32, 206, 19, 221, 11,
+ 226, 92, 177, 90, 33, 124, 183, 107, 244, 184, 152, 161, 163, 19, 199,
+ 71, 39, 14, 33, 206, 182, 133, 154, 235, 182, 123, 65, 188, 79, 96,
+ 250, 95, 134, 212, 204, 211, 24, 134, 137, 114, 80, 153, 80, 135, 210,
+ 196, 54, 138, 139, 23, 218, 9, 146, 28, 147, 0, 251, 212, 184, 209,
+ 241, 32, 150, 221, 100, 233, 174, 89, 101, 10, 19, 239, 135, 83, 31,
+ 32, 126, 175, 45, 47, 114, 217, 203, 135, 50, 89, 246, 207, 162, 142,
+ 211, 157, 47, 94, 184, 158, 5, 25, 99, 146, 98, 146, 5, 192, 172,
+ 86, 84, 169, 19, 174, 218, 218, 126, 188, 143, 183, 219, 7, 200, 217,
+ 194, 134, 1, 254, 104, 8, 253, 131, 131, 228, 229, 37, 140, 188, 184,
+ 38, 114, 175, 218, 142, 103, 82, 92, 50, 113, 181, 229, 79, 205, 177,
+ 29, 79, 188, 183, 140, 167, 206, 60, 158, 193, 194, 219, 72, 95, 111,
+ 60, 81, 38, 42, 159, 160, 203, 87, 29, 199, 19, 101, 180, 172, 79,
+ 187, 9, 15, 48, 217, 142, 39, 222, 219, 143, 167, 197, 206, 198, 153,
+ 71, 211, 126, 68, 97, 60, 155, 187, 43, 47, 202, 56, 142, 89, 127,
+ 233, 38, 58, 158, 156, 48, 158, 160, 151, 193, 46, 247, 95, 175, 108,
+ 199, 19, 239, 233, 120, 166, 142, 123, 172, 240, 16, 96, 249, 112, 55,
+ 72, 66, 62, 148, 201, 162, 159, 212, 62, 216, 202, 231, 250, 124, 231,
+ 165, 173, 124, 120, 79, 229, 11, 8, 115, 95, 190, 210, 82, 250, 200,
+ 200, 135, 54, 43, 231, 165, 131, 124, 46, 205, 111, 234, 11, 59, 125,
+ 124, 97, 149, 47, 61, 144, 202, 231, 245, 218, 242, 161, 76, 84, 62,
+ 180, 167, 196, 81, 62, 151, 238, 41, 253, 185, 173, 124, 120, 79, 229,
+ 83, 109, 116, 127, 252, 138, 75, 200, 135, 50, 81, 249, 208, 214, 171,
+ 94, 56, 200, 215, 216, 229, 254, 234, 153, 173, 124, 120, 79, 229, 211,
+ 125, 234, 190, 124, 133, 37, 228, 67, 153, 168, 124, 232, 135, 52, 207,
+ 29, 228, 107, 226, 138, 111, 238, 83, 91, 249, 240, 158, 202, 151, 179,
+ 208, 253, 249, 149, 146, 15, 101, 162, 242, 161, 143, 212, 61, 115, 144,
+ 175, 169, 43, 190, 74, 59, 249, 148, 140, 124, 233, 183, 168, 124, 133,
+ 100, 229, 43, 47, 33, 31, 202, 196, 158, 207, 234, 159, 58, 200, 215,
+ 204, 229, 25, 230, 63, 182, 242, 225, 61, 149, 47, 247, 35, 247, 231,
+ 183, 138, 19, 249, 210, 112, 126, 159, 196, 123, 77, 167, 246, 234, 177,
+ 109, 140, 130, 47, 132, 75, 154, 173, 52, 12, 104, 84, 215, 80, 253,
+ 131, 249, 65, 182, 123, 51, 199, 253, 179, 231, 129, 78, 1, 243, 74,
+ 198, 212, 194, 187, 196, 71, 211, 131, 241, 187, 11, 21, 227, 183, 172,
+ 199, 251, 23, 203, 18, 214, 255, 176, 96, 81, 45, 74, 151, 8, 124,
+ 251, 1, 223, 122, 34, 223, 132, 152, 145, 227, 226, 146, 228, 109, 118,
+ 154, 40, 39, 149, 217, 248, 8, 230, 252, 137, 85, 110, 47, 79, 233,
+ 115, 146, 225, 175, 82, 248, 249, 179, 84, 33, 126, 29, 190, 10, 169,
+ 164, 250, 53, 116, 199, 211, 20, 126, 77, 205, 129, 97, 245, 14, 212,
+ 21, 190, 171, 238, 229, 59, 112, 127, 14, 148, 77, 189, 176, 70, 248,
+ 174, 249, 254, 115, 245, 66, 239, 4, 127, 186, 119, 191, 201, 252, 221,
+ 245, 65, 89, 115, 50, 218, 77, 43, 210, 184, 66, 185, 194, 130, 204,
+ 67, 99, 70, 141, 77, 244, 135, 189, 69, 178, 188, 204, 40, 39, 149,
+ 57, 247, 97, 188, 23, 59, 214, 174, 100, 254, 12, 218, 206, 44, 22,
+ 186, 111, 194, 217, 81, 33, 171, 74, 157, 223, 59, 23, 238, 79, 143,
+ 234, 185, 111, 198, 194, 187, 194, 247, 227, 223, 221, 223, 35, 116, 49,
+ 244, 43, 182, 246, 62, 161, 15, 95, 23, 248, 43, 164, 247, 227, 189,
+ 161, 63, 188, 50, 203, 92, 235, 66, 98, 198, 199, 77, 67, 50, 195,
+ 238, 238, 17, 100, 78, 142, 27, 20, 23, 237, 166, 204, 40, 39, 149,
+ 89, 5, 48, 246, 193, 29, 153, 191, 130, 182, 115, 175, 105, 67, 74,
+ 239, 138, 10, 137, 243, 57, 27, 186, 239, 89, 10, 191, 80, 217, 57,
+ 172, 100, 204, 105, 65, 230, 210, 5, 59, 239, 199, 178, 221, 13, 190,
+ 23, 198, 121, 112, 193, 111, 67, 248, 37, 223, 238, 61, 47, 142, 243,
+ 246, 6, 199, 130, 134, 110, 73, 207, 56, 197, 63, 51, 203, 28, 157,
+ 152, 52, 54, 201, 181, 208, 84, 102, 21, 35, 179, 246, 1, 196, 71,
+ 15, 221, 147, 249, 224, 243, 20, 126, 99, 196, 201, 61, 186, 97, 123,
+ 247, 234, 238, 53, 223, 239, 253, 87, 10, 175, 184, 181, 123, 127, 212,
+ 227, 16, 225, 121, 229, 202, 187, 187, 195, 218, 66, 89, 239, 243, 45,
+ 133, 62, 248, 126, 223, 98, 95, 197, 175, 187, 133, 236, 22, 101, 62,
+ 186, 46, 36, 176, 207, 39, 202, 192, 67, 185, 251, 133, 179, 249, 81,
+ 49, 201, 209, 114, 114, 91, 222, 197, 248, 192, 42, 179, 254, 111, 240,
+ 1, 110, 202, 236, 108, 13, 22, 43, 181, 122, 187, 49, 178, 189, 16,
+ 16, 7, 63, 235, 45, 172, 65, 221, 237, 87, 194, 26, 60, 247, 243,
+ 246, 218, 247, 31, 159, 89, 79, 233, 74, 54, 59, 158, 113, 186, 192,
+ 209, 237, 154, 155, 61, 132, 117, 57, 114, 236, 168, 65, 209, 137, 238,
+ 173, 65, 148, 147, 202, 156, 126, 31, 246, 55, 15, 94, 95, 230, 247,
+ 54, 181, 202, 24, 55, 38, 184, 54, 222, 253, 82, 96, 181, 48, 126,
+ 217, 33, 53, 4, 153, 149, 15, 252, 191, 120, 117, 226, 75, 139, 204,
+ 115, 171, 182, 200, 168, 115, 236, 122, 70, 234, 137, 80, 65, 230, 228,
+ 216, 209, 137, 209, 19, 220, 147, 25, 229, 164, 50, 231, 228, 194, 190,
+ 234, 239, 215, 151, 185, 235, 160, 105, 25, 161, 187, 102, 9, 50, 159,
+ 173, 91, 93, 144, 153, 12, 60, 33, 188, 166, 108, 237, 198, 102, 27,
+ 114, 219, 101, 91, 108, 93, 181, 58, 75, 130, 118, 39, 148, 201, 56,
+ 253, 219, 118, 33, 15, 61, 58, 121, 100, 180, 220, 195, 52, 42, 51,
+ 202, 105, 209, 231, 170, 177, 94, 216, 7, 70, 102, 165, 187, 50, 163,
+ 30, 244, 251, 114, 94, 80, 179, 47, 139, 9, 227, 250, 237, 170, 221,
+ 194, 243, 244, 250, 57, 105, 27, 240, 254, 201, 241, 254, 27, 2, 254,
+ 46, 93, 147, 210, 205, 78, 90, 147, 241, 211, 59, 5, 27, 71, 206,
+ 230, 4, 153, 7, 39, 70, 199, 199, 141, 29, 229, 150, 204, 40, 167,
+ 69, 159, 171, 196, 122, 97, 31, 94, 119, 156, 79, 70, 85, 220, 238,
+ 125, 171, 136, 16, 163, 29, 110, 84, 172, 49, 150, 149, 93, 244, 129,
+ 112, 223, 33, 180, 238, 182, 57, 202, 140, 109, 156, 72, 119, 196, 187,
+ 110, 70, 192, 215, 21, 131, 125, 118, 157, 222, 142, 120, 49, 209, 114,
+ 214, 153, 209, 231, 42, 86, 153, 211, 43, 199, 122, 97, 31, 220, 145,
+ 249, 200, 31, 41, 60, 247, 217, 151, 33, 190, 201, 203, 246, 30, 83,
+ 158, 218, 223, 126, 107, 10, 255, 147, 71, 199, 3, 79, 90, 148, 22,
+ 236, 198, 242, 151, 29, 194, 213, 80, 54, 255, 157, 6, 194, 125, 245,
+ 37, 149, 246, 133, 158, 172, 177, 111, 181, 104, 55, 86, 53, 90, 16,
+ 124, 225, 114, 151, 224, 117, 69, 218, 10, 231, 203, 177, 99, 71, 197,
+ 36, 202, 24, 59, 139, 62, 87, 182, 202, 156, 83, 41, 214, 11, 251,
+ 224, 142, 204, 107, 110, 167, 240, 87, 27, 165, 238, 171, 176, 238, 242,
+ 222, 125, 250, 239, 195, 202, 111, 76, 225, 183, 79, 238, 22, 254, 145,
+ 161, 163, 32, 227, 157, 119, 187, 29, 184, 187, 62, 133, 63, 247, 97,
+ 9, 225, 29, 42, 153, 131, 226, 246, 29, 219, 87, 44, 172, 252, 75,
+ 179, 204, 119, 213, 33, 25, 218, 235, 189, 130, 55, 221, 231, 5, 29,
+ 26, 59, 50, 94, 206, 165, 88, 245, 185, 146, 85, 102, 37, 192, 216,
+ 7, 119, 100, 238, 15, 62, 37, 56, 76, 21, 114, 48, 236, 241, 222,
+ 223, 110, 253, 18, 58, 1, 252, 244, 142, 159, 223, 13, 27, 115, 116,
+ 156, 32, 115, 231, 251, 239, 238, 191, 14, 101, 185, 57, 171, 4, 159,
+ 178, 98, 235, 216, 125, 199, 23, 173, 221, 59, 89, 28, 103, 245, 189,
+ 78, 25, 151, 135, 254, 180, 93, 105, 200, 10, 16, 244, 57, 58, 49,
+ 193, 93, 159, 162, 100, 100, 214, 84, 4, 125, 174, 228, 158, 204, 187,
+ 115, 83, 248, 132, 65, 53, 246, 104, 31, 166, 135, 4, 206, 75, 223,
+ 127, 237, 80, 10, 95, 126, 90, 192, 129, 49, 19, 2, 4, 95, 221,
+ 124, 106, 64, 120, 213, 195, 16, 111, 92, 58, 36, 188, 203, 166, 64,
+ 191, 192, 208, 19, 23, 102, 182, 56, 36, 202, 124, 175, 76, 227, 237,
+ 11, 78, 126, 26, 212, 237, 214, 150, 237, 212, 167, 200, 201, 77, 101,
+ 70, 57, 169, 204, 9, 21, 98, 189, 148, 110, 202, 236, 204, 110, 164,
+ 156, 43, 24, 252, 119, 61, 95, 97, 205, 253, 120, 83, 41, 204, 249,
+ 239, 138, 115, 219, 241, 190, 232, 158, 141, 219, 127, 234, 153, 20, 72,
+ 215, 224, 170, 155, 126, 65, 233, 23, 210, 50, 14, 55, 127, 25, 68,
+ 215, 96, 98, 220, 176, 88, 119, 116, 3, 229, 164, 50, 167, 149, 143,
+ 245, 194, 62, 184, 35, 243, 47, 176, 6, 189, 27, 71, 182, 240, 235,
+ 144, 30, 82, 217, 120, 114, 255, 68, 88, 111, 107, 182, 118, 56, 176,
+ 255, 162, 121, 156, 215, 165, 119, 8, 207, 128, 178, 230, 161, 159, 183,
+ 16, 124, 76, 90, 163, 208, 0, 159, 223, 247, 208, 113, 78, 232, 241,
+ 65, 112, 246, 186, 61, 193, 95, 126, 29, 97, 179, 6, 93, 201, 77,
+ 101, 70, 57, 169, 204, 217, 190, 177, 94, 216, 7, 119, 100, 174, 126,
+ 39, 133, 95, 31, 172, 15, 125, 191, 251, 223, 33, 247, 87, 100, 135,
+ 205, 255, 42, 133, 239, 180, 76, 27, 126, 199, 63, 70, 144, 249, 193,
+ 68, 237, 129, 87, 95, 166, 240, 95, 100, 112, 194, 54, 59, 35, 42,
+ 37, 244, 227, 208, 151, 251, 62, 16, 215, 160, 255, 239, 253, 130, 139,
+ 254, 84, 47, 35, 123, 246, 141, 0, 203, 26, 148, 25, 104, 203, 187,
+ 251, 125, 173, 50, 19, 128, 177, 15, 238, 200, 220, 9, 214, 160, 41,
+ 116, 102, 200, 210, 220, 59, 45, 166, 14, 185, 29, 218, 3, 214, 219,
+ 161, 161, 113, 97, 27, 106, 14, 19, 98, 162, 164, 129, 113, 251, 155,
+ 65, 153, 97, 125, 1, 97, 77, 94, 220, 19, 31, 82, 61, 219, 115,
+ 223, 5, 113, 156, 107, 141, 168, 17, 172, 25, 210, 44, 40, 186, 207,
+ 198, 64, 102, 13, 186, 148, 154, 202, 76, 24, 153, 3, 202, 197, 122,
+ 97, 31, 220, 145, 217, 15, 214, 224, 59, 41, 197, 246, 20, 235, 181,
+ 109, 239, 136, 187, 25, 251, 103, 27, 193, 246, 229, 4, 31, 232, 182,
+ 53, 80, 144, 113, 221, 213, 224, 240, 163, 80, 54, 106, 237, 187, 194,
+ 26, 188, 246, 91, 192, 190, 39, 159, 110, 110, 97, 20, 101, 38, 3,
+ 74, 52, 234, 240, 105, 169, 224, 62, 41, 5, 236, 215, 160, 164, 220,
+ 84, 102, 148, 147, 202, 172, 43, 11, 242, 186, 41, 115, 79, 24, 231,
+ 163, 97, 109, 247, 62, 136, 222, 191, 215, 123, 217, 245, 208, 56, 24,
+ 211, 201, 159, 13, 14, 27, 180, 53, 84, 144, 217, 56, 111, 240, 254,
+ 149, 80, 118, 253, 210, 9, 97, 220, 179, 74, 132, 239, 155, 178, 250,
+ 72, 200, 70, 81, 230, 73, 55, 87, 103, 172, 59, 154, 153, 209, 179,
+ 72, 197, 12, 235, 62, 197, 181, 114, 88, 246, 131, 101, 173, 50, 167,
+ 150, 137, 245, 194, 62, 184, 35, 243, 18, 104, 59, 84, 23, 25, 90,
+ 239, 97, 220, 222, 150, 29, 127, 222, 59, 11, 238, 87, 174, 25, 176,
+ 111, 226, 186, 91, 130, 61, 206, 205, 237, 31, 154, 4, 253, 242, 159,
+ 120, 68, 232, 67, 177, 54, 127, 236, 157, 212, 230, 200, 190, 221, 226,
+ 62, 101, 217, 184, 155, 129, 154, 161, 177, 193, 79, 251, 173, 204, 176,
+ 238, 83, 220, 147, 25, 229, 180, 236, 7, 75, 199, 122, 9, 99, 237,
+ 134, 204, 95, 66, 219, 53, 198, 118, 221, 91, 191, 85, 231, 189, 159,
+ 175, 58, 27, 186, 19, 246, 36, 103, 211, 58, 135, 61, 249, 235, 180,
+ 32, 51, 191, 164, 243, 254, 29, 80, 86, 242, 240, 247, 194, 56, 151,
+ 88, 244, 237, 222, 128, 218, 217, 33, 84, 159, 183, 127, 118, 109, 91,
+ 197, 140, 45, 219, 195, 127, 217, 18, 204, 236, 83, 220, 210, 103, 148,
+ 115, 58, 115, 46, 128, 125, 112, 71, 230, 72, 216, 167, 44, 79, 56,
+ 18, 82, 179, 171, 49, 164, 224, 95, 45, 247, 247, 189, 151, 194, 55,
+ 189, 118, 112, 255, 119, 105, 17, 130, 221, 216, 248, 240, 96, 88, 111,
+ 40, 43, 94, 43, 66, 24, 231, 238, 207, 194, 67, 181, 25, 109, 246,
+ 141, 16, 101, 126, 209, 162, 80, 224, 195, 234, 47, 183, 246, 186, 186,
+ 97, 187, 221, 62, 197, 165, 62, 123, 139, 207, 238, 103, 80, 125, 134,
+ 61, 55, 246, 129, 230, 22, 96, 62, 1, 205, 45, 192, 247, 202, 96,
+ 174, 1, 155, 91, 16, 23, 31, 68, 236, 147, 96, 173, 57, 51, 121,
+ 203, 4, 162, 188, 85, 11, 173, 185, 5, 248, 44, 32, 245, 93, 176,
+ 191, 141, 29, 115, 102, 2, 210, 31, 43, 132, 11, 234, 115, 123, 130,
+ 108, 90, 215, 121, 53, 125, 220, 204, 45, 192, 45, 86, 94, 115, 11,
+ 134, 139, 185, 5, 135, 123, 19, 75, 110, 193, 88, 23, 185, 5, 11,
+ 180, 154, 140, 97, 191, 52, 48, 60, 122, 220, 66, 67, 191, 155, 26,
+ 103, 247, 221, 212, 109, 245, 155, 137, 223, 87, 21, 254, 50, 40, 158,
+ 16, 203, 13, 237, 100, 44, 94, 231, 79, 254, 163, 228, 176, 198, 255,
+ 137, 239, 166, 202, 231, 124, 57, 230, 204, 232, 85, 16, 187, 194, 165,
+ 43, 33, 94, 74, 243, 21, 48, 208, 124, 185, 47, 92, 1, 161, 253,
+ 186, 220, 28, 245, 79, 143, 102, 171, 221, 205, 45, 16, 190, 231, 45,
+ 234, 4, 103, 151, 115, 128, 114, 73, 230, 197, 74, 228, 7, 176, 121,
+ 177, 72, 183, 73, 21, 107, 243, 76, 3, 251, 40, 151, 23, 59, 42,
+ 105, 152, 152, 26, 235, 60, 61, 32, 7, 198, 71, 163, 138, 117, 254,
+ 189, 81, 149, 181, 47, 56, 142, 52, 47, 22, 105, 254, 39, 242, 98,
+ 177, 141, 55, 145, 23, 155, 6, 115, 157, 51, 208, 121, 159, 104, 185,
+ 224, 255, 7, 198, 90, 158, 133, 34, 141, 179, 188, 88, 196, 113, 149,
+ 23, 27, 151, 48, 58, 122, 112, 242, 216, 232, 100, 24, 91, 103, 143,
+ 80, 178, 223, 141, 181, 121, 22, 138, 247, 175, 155, 23, 75, 237, 39,
+ 218, 167, 25, 118, 50, 97, 93, 3, 148, 23, 234, 154, 208, 56, 114,
+ 128, 185, 109, 107, 236, 156, 56, 122, 172, 19, 77, 203, 169, 111, 238,
+ 111, 3, 145, 134, 210, 39, 0, 140, 252, 108, 246, 191, 206, 88, 248,
+ 91, 233, 19, 24, 122, 37, 192, 200, 143, 238, 249, 157, 183, 14, 122,
+ 86, 194, 74, 175, 100, 232, 211, 251, 195, 88, 193, 189, 249, 156, 67,
+ 138, 26, 244, 166, 148, 149, 30, 105, 40, 189, 22, 96, 228, 39, 158,
+ 237, 72, 50, 208, 151, 177, 210, 107, 25, 250, 220, 126, 176, 175, 132,
+ 123, 241, 60, 75, 146, 62, 173, 156, 149, 30, 105, 40, 125, 42, 192,
+ 200, 79, 60, 147, 150, 238, 192, 96, 43, 125, 42, 67, 31, 0, 48,
+ 242, 179, 217, 203, 35, 151, 247, 109, 201, 141, 117, 173, 244, 1, 12,
+ 125, 118, 223, 88, 175, 84, 134, 94, 74, 7, 52, 126, 204, 252, 247,
+ 101, 230, 31, 96, 228, 103, 221, 151, 59, 239, 66, 90, 109, 102, 254,
+ 25, 122, 37, 192, 200, 143, 221, 83, 56, 229, 80, 140, 153, 127, 134,
+ 62, 253, 29, 24, 59, 184, 103, 247, 170, 206, 232, 245, 53, 153, 249,
+ 127, 135, 153, 127, 128, 149, 86, 122, 201, 37, 144, 83, 132, 153, 127,
+ 134, 62, 183, 15, 204, 63, 220, 219, 239, 151, 237, 89, 232, 170, 51,
+ 243, 223, 135, 153, 127, 128, 181, 182, 244, 78, 101, 48, 22, 98, 230,
+ 159, 161, 15, 0, 24, 249, 49, 207, 7, 156, 14, 95, 142, 142, 153,
+ 127, 134, 62, 187, 55, 204, 191, 133, 94, 218, 2, 164, 121, 49, 243,
+ 223, 155, 153, 127, 128, 145, 31, 115, 214, 239, 92, 1, 170, 48, 243,
+ 207, 208, 43, 1, 70, 126, 108, 12, 238, 116, 254, 10, 48, 243, 207,
+ 208, 167, 247, 130, 249, 71, 122, 230, 252, 219, 25, 125, 78, 69, 102,
+ 254, 123, 49, 243, 15, 176, 210, 74, 47, 169, 129, 58, 15, 102, 254,
+ 25, 122, 140, 241, 144, 159, 195, 25, 188, 253, 252, 149, 103, 230, 191,
+ 167, 149, 158, 136, 252, 28, 98, 99, 123, 17, 166, 60, 86, 208, 248,
+ 23, 99, 94, 26, 255, 226, 187, 204, 48, 30, 182, 139, 127, 37, 223,
+ 111, 248, 186, 241, 175, 205, 115, 126, 136, 127, 85, 221, 98, 189, 140,
+ 69, 156, 196, 191, 127, 67, 236, 11, 151, 177, 43, 200, 213, 22, 230,
+ 182, 219, 219, 248, 247, 223, 20, 255, 234, 96, 62, 116, 221, 98, 189,
+ 242, 45, 155, 16, 105, 189, 94, 252, 75, 117, 194, 62, 254, 69, 185,
+ 242, 27, 255, 206, 235, 102, 141, 165, 112, 192, 80, 79, 165, 226, 32,
+ 212, 81, 186, 14, 141, 93, 242, 30, 7, 33, 13, 165, 215, 1, 140,
+ 252, 242, 18, 7, 233, 24, 122, 130, 244, 93, 242, 22, 7, 17, 134,
+ 62, 173, 51, 204, 107, 151, 188, 197, 65, 72, 67, 233, 53, 0, 35,
+ 191, 188, 196, 65, 26, 134, 62, 39, 42, 214, 11, 249, 229, 37, 14,
+ 66, 26, 74, 175, 7, 24, 249, 229, 37, 14, 210, 51, 244, 42, 128,
+ 145, 95, 94, 226, 32, 21, 67, 111, 236, 4, 251, 194, 168, 188, 197,
+ 65, 72, 99, 153, 127, 128, 145, 95, 94, 226, 32, 29, 67, 79, 0,
+ 70, 126, 121, 137, 131, 8, 67, 159, 214, 17, 230, 191, 83, 222, 226,
+ 32, 164, 177, 204, 63, 192, 164, 83, 222, 226, 32, 13, 67, 159, 211,
+ 1, 230, 191, 99, 222, 226, 32, 164, 177, 204, 63, 192, 154, 142, 121,
+ 139, 131, 244, 12, 189, 10, 96, 228, 151, 151, 56, 72, 197, 208, 27,
+ 219, 195, 252, 119, 200, 91, 28, 132, 52, 150, 249, 7, 24, 249, 229,
+ 37, 14, 210, 49, 244, 4, 96, 228, 151, 151, 56, 136, 48, 244, 105,
+ 237, 96, 254, 219, 231, 45, 14, 66, 26, 203, 252, 3, 76, 218, 231,
+ 45, 14, 210, 48, 244, 232, 235, 145, 95, 94, 226, 32, 164, 97, 227,
+ 32, 77, 187, 188, 197, 65, 24, 251, 52, 101, 232, 49, 46, 178, 198,
+ 65, 248, 107, 114, 142, 195, 159, 223, 239, 193, 59, 251, 83, 181, 200,
+ 219, 59, 234, 126, 241, 244, 62, 232, 234, 123, 240, 111, 250, 93, 150,
+ 246, 223, 243, 148, 251, 30, 60, 202, 18, 212, 182, 136, 230, 175, 166,
+ 211, 223, 208, 247, 224, 243, 247, 247, 127, 237, 187, 159, 81, 173, 9,
+ 193, 135, 221, 248, 110, 195, 32, 106, 191, 236, 222, 165, 16, 213, 154,
+ 126, 119, 185, 185, 211, 177, 208, 61, 122, 252, 198, 95, 49, 203, 17,
+ 87, 207, 106, 217, 252, 62, 79, 27, 92, 218, 31, 236, 3, 237, 15,
+ 126, 31, 154, 125, 119, 163, 165, 63, 129, 1, 78, 219, 204, 126, 232,
+ 186, 63, 250, 174, 102, 94, 170, 8, 176, 51, 17, 174, 215, 155, 39,
+ 177, 126, 15, 97, 95, 84, 77, 152, 13, 77, 227, 74, 61, 95, 6,
+ 31, 0, 56, 62, 120, 142, 218, 177, 63, 156, 67, 124, 40, 124, 39,
+ 3, 218, 105, 36, 242, 219, 31, 245, 133, 38, 1, 104, 145, 143, 240,
+ 172, 58, 69, 97, 194, 178, 216, 224, 57, 89, 108, 25, 124, 236, 24,
+ 234, 80, 166, 111, 156, 108, 71, 75, 191, 251, 130, 253, 170, 103, 25,
+ 7, 15, 136, 102, 57, 8, 251, 77, 130, 12, 237, 196, 254, 54, 176,
+ 153, 27, 103, 239, 168, 53, 207, 145, 233, 229, 203, 151, 166, 165, 75,
+ 151, 10, 215, 139, 23, 47, 164, 102, 149, 206, 23, 206, 17, 157, 47,
+ 252, 254, 47, 171, 131, 214, 249, 146, 120, 79, 190, 204, 124, 25, 121,
+ 51, 175, 4, 53, 248, 37, 141, 235, 249, 242, 102, 230, 76, 228, 46,
+ 228, 33, 55, 153, 222, 80, 115, 232, 204, 57, 181, 156, 254, 89, 158,
+ 39, 106, 204, 243, 133, 252, 112, 174, 19, 132, 185, 22, 115, 11, 82,
+ 136, 9, 203, 112, 190, 236, 202, 140, 67, 237, 202, 246, 66, 89, 178,
+ 29, 109, 240, 244, 134, 198, 227, 130, 44, 214, 50, 144, 207, 184, 231,
+ 204, 185, 44, 187, 50, 205, 126, 39, 101, 135, 236, 104, 233, 89, 47,
+ 142, 83, 61, 139, 141, 226, 72, 65, 130, 63, 109, 208, 83, 200, 179,
+ 45, 0, 119, 8, 43, 64, 47, 60, 225, 14, 97, 220, 117, 121, 17,
+ 79, 1, 22, 190, 215, 195, 153, 199, 184, 129, 141, 157, 115, 161, 35,
+ 41, 41, 41, 236, 229, 218, 27, 230, 157, 15, 247, 47, 231, 67, 117,
+ 31, 245, 221, 98, 123, 193, 127, 179, 239, 111, 176, 232, 190, 196, 247,
+ 238, 211, 31, 72, 235, 190, 6, 248, 42, 67, 204, 188, 210, 51, 75,
+ 122, 212, 33, 81, 46, 117, 191, 43, 49, 255, 96, 169, 147, 254, 182,
+ 52, 95, 246, 186, 79, 159, 117, 152, 203, 45, 207, 97, 194, 173, 123,
+ 234, 180, 2, 230, 103, 22, 61, 10, 226, 175, 80, 71, 9, 107, 162,
+ 171, 184, 44, 217, 239, 204, 163, 30, 154, 203, 136, 179, 50, 98, 87,
+ 70, 28, 241, 244, 70, 137, 50, 59, 90, 163, 51, 126, 248, 142, 166,
+ 198, 78, 240, 236, 101, 57, 200, 57, 148, 9, 120, 45, 29, 249, 25,
+ 53, 142, 101, 44, 158, 130, 182, 235, 76, 230, 150, 142, 109, 24, 157,
+ 180, 235, 48, 126, 196, 121, 153, 209, 201, 152, 26, 157, 180, 235, 116,
+ 62, 90, 58, 226, 57, 200, 162, 177, 47, 227, 204, 188, 236, 199, 165,
+ 165, 253, 24, 112, 102, 58, 39, 120, 206, 218, 112, 24, 43, 137, 50,
+ 135, 254, 74, 148, 57, 140, 115, 99, 39, 178, 56, 105, 67, 160, 117,
+ 210, 174, 109, 25, 252, 241, 142, 122, 37, 240, 215, 56, 41, 35, 142,
+ 101, 122, 39, 99, 224, 172, 93, 7, 221, 213, 176, 186, 207, 200, 119,
+ 208, 201, 56, 27, 157, 204, 165, 209, 137, 124, 7, 109, 117, 215, 232,
+ 132, 159, 94, 162, 93, 7, 126, 18, 101, 14, 242, 101, 74, 224, 57,
+ 41, 115, 218, 95, 103, 253, 112, 82, 166, 119, 50, 6, 196, 73, 153,
+ 62, 195, 201, 250, 176, 111, 215, 104, 50, 165, 24, 157, 172, 203, 12,
+ 39, 54, 204, 232, 100, 237, 27, 157, 216, 23, 39, 101, 246, 50, 147,
+ 131, 78, 218, 61, 248, 202, 100, 50, 56, 177, 37, 70, 39, 246, 202,
+ 89, 187, 7, 157, 216, 48, 59, 61, 208, 59, 195, 35, 206, 203, 28,
+ 100, 118, 38, 139, 51, 126, 78, 250, 171, 119, 160, 69, 63, 131, 65,
+ 9, 250, 188, 122, 150, 133, 82, 90, 136, 208, 148, 226, 243, 134, 2,
+ 16, 193, 208, 223, 198, 196, 39, 244, 74, 209, 135, 41, 136, 249, 21,
+ 125, 158, 16, 177, 21, 20, 226, 27, 164, 84, 194, 157, 57, 217, 220,
+ 155, 20, 130, 88, 7, 99, 160, 106, 112, 21, 133, 59, 111, 1, 46,
+ 76, 124, 72, 17, 82, 28, 224, 96, 248, 191, 8, 212, 40, 133, 242,
+ 98, 80, 83, 156, 148, 5, 184, 4, 252, 143, 245, 165, 197, 35, 244,
+ 18, 164, 36, 41, 37, 192, 126, 164, 12, 64, 37, 5, 28, 252, 30,
+ 95, 41, 1, 31, 191, 215, 91, 12, 160, 82, 66, 121, 5, 226, 11,
+ 126, 182, 156, 0, 151, 3, 168, 50, 169, 36, 224, 148, 135, 154, 114,
+ 164, 34, 192, 203, 225, 255, 114, 80, 90, 7, 224, 57, 128, 81, 21,
+ 90, 175, 44, 224, 248, 18, 21, 220, 85, 17, 104, 171, 66, 59, 37,
+ 4, 217, 33, 198, 128, 150, 75, 66, 137, 82, 40, 41, 1, 253, 175,
+ 46, 148, 87, 7, 136, 39, 53, 5, 184, 50, 212, 84, 39, 53, 4,
+ 184, 6, 64, 53, 73, 61, 1, 174, 69, 234, 146, 48, 82, 91, 104,
+ 171, 14, 180, 90, 23, 74, 16, 174, 11, 88, 245, 160, 6, 113, 42,
+ 1, 117, 13, 40, 65, 184, 62, 9, 36, 65, 196, 95, 128, 253, 1,
+ 106, 64, 2, 0, 142, 36, 33, 80, 227, 79, 26, 10, 180, 13, 1,
+ 10, 32, 141, 0, 62, 13, 24, 193, 164, 49, 96, 33, 78, 32, 105,
+ 6, 119, 65, 2, 109, 48, 105, 66, 58, 66, 13, 150, 55, 35, 157,
+ 224, 46, 88, 40, 175, 73, 112, 139, 219, 84, 128, 155, 2, 212, 9,
+ 106, 17, 174, 7, 53, 77, 73, 115, 1, 110, 14, 80, 51, 224, 134,
+ 112, 11, 18, 10, 45, 135, 8, 237, 214, 6, 121, 67, 161, 4, 225,
+ 80, 192, 10, 132, 26, 196, 9, 3, 234, 230, 80, 162, 20, 206, 244,
+ 11, 128, 129, 8, 23, 224, 112, 128, 212, 164, 139, 0, 243, 80, 19,
+ 14, 237, 41, 5, 61, 11, 135, 210, 78, 2, 220, 146, 68, 144, 86,
+ 128, 165, 20, 178, 114, 10, 194, 93, 75, 1, 142, 32, 173, 65, 242,
+ 86, 130, 110, 96, 92, 221, 26, 74, 16, 110, 5, 165, 109, 73, 27,
+ 1, 110, 3, 80, 123, 210, 14, 224, 161, 192, 161, 21, 220, 107, 5,
+ 90, 45, 64, 237, 72, 7, 161, 239, 77, 72, 20, 233, 12, 35, 129,
+ 112, 39, 104, 53, 10, 74, 16, 39, 10, 176, 58, 64, 13, 150, 119,
+ 1, 106, 45, 148, 40, 197, 152, 12, 38, 91, 136, 255, 26, 176, 206,
+ 195, 85, 252, 58, 97, 194, 4, 83, 100, 100, 164, 240, 121, 246, 236,
+ 89, 172, 249, 39, 133, 216, 127, 233, 66, 158, 79, 76, 76, 140, 41,
+ 36, 36, 196, 212, 186, 117, 107, 211, 196, 137, 19, 205, 124, 184, 188,
+ 243, 65, 122, 228, 131, 252, 242, 195, 231, 201, 147, 39, 216, 31, 225,
+ 83, 252, 141, 226, 215, 234, 23, 142, 75, 131, 6, 13, 76, 205, 154,
+ 53, 51, 45, 88, 176, 224, 181, 249, 168, 84, 42, 147, 183, 183, 183,
+ 169, 116, 233, 210, 216, 191, 215, 238, 23, 210, 163, 13, 196, 171, 66,
+ 133, 10, 175, 205, 167, 84, 169, 82, 22, 62, 208, 191, 215, 238, 23,
+ 229, 33, 94, 111, 132, 15, 140, 211, 107, 247, 235, 77, 241, 161, 227,
+ 131, 159, 176, 62, 164, 251, 101, 75, 103, 207, 87, 208, 31, 208, 27,
+ 65, 127, 222, 196, 56, 227, 252, 187, 156, 119, 25, 121, 80, 15, 113,
+ 125, 33, 159, 55, 49, 206, 56, 62, 111, 162, 95, 226, 120, 231, 139,
+ 15, 174, 47, 113, 157, 189, 17, 253, 177, 200, 227, 241, 223, 235, 151,
+ 56, 190, 212, 78, 191, 17, 253, 201, 207, 248, 136, 250, 71, 237, 116,
+ 190, 198, 89, 161, 80, 228, 123, 93, 208, 245, 37, 218, 251, 124, 249,
+ 47, 240, 55, 166, 201, 147, 39, 231, 203, 239, 208, 245, 37, 250, 195,
+ 215, 230, 35, 250, 99, 161, 95, 249, 241, 59, 162, 125, 23, 198, 25,
+ 198, 59, 223, 235, 75, 244, 63, 249, 210, 31, 26, 39, 228, 215, 127,
+ 209, 184, 37, 63, 250, 67, 249, 188, 41, 251, 99, 99, 55, 184, 255,
+ 46, 159, 55, 225, 151, 169, 253, 201, 47, 159, 55, 229, 119, 168, 253,
+ 201, 239, 248, 188, 41, 191, 44, 198, 151, 111, 204, 254, 228, 215, 174,
+ 138, 241, 247, 27, 179, 63, 111, 194, 239, 160, 254, 188, 137, 245, 133,
+ 243, 254, 166, 236, 79, 126, 227, 4, 113, 63, 144, 111, 251, 35, 218,
+ 247, 55, 182, 255, 18, 215, 217, 107, 247, 75, 244, 127, 111, 108, 255,
+ 37, 174, 179, 124, 239, 191, 100, 227, 112, 55, 214, 5, 213, 159, 55,
+ 181, 255, 202, 175, 254, 96, 252, 147, 223, 253, 23, 187, 143, 123, 83,
+ 251, 175, 252, 172, 47, 186, 207, 125, 83, 251, 175, 252, 246, 75, 180,
+ 239, 52, 222, 204, 151, 254, 80, 255, 149, 159, 184, 69, 244, 127, 111,
+ 196, 127, 209, 184, 197, 133, 254, 88, 114, 36, 90, 88, 159, 59, 226,
+ 247, 7, 217, 247, 110, 71, 181, 142, 138, 73, 138, 149, 206, 203, 200,
+ 249, 197, 245, 51, 119, 93, 19, 51, 175, 101, 71, 58, 121, 213, 209,
+ 118, 116, 249, 220, 177, 59, 92, 29, 173, 188, 51, 105, 249, 181, 19,
+ 69, 53, 213, 43, 239, 116, 235, 153, 251, 251, 248, 124, 17, 218, 105,
+ 36, 242, 67, 90, 205, 212, 245, 251, 216, 243, 225, 156, 19, 47, 121,
+ 219, 50, 133, 80, 182, 106, 193, 193, 3, 44, 94, 141, 225, 94, 26,
+ 103, 101, 187, 38, 36, 218, 60, 75, 159, 100, 80, 104, 126, 109, 52,
+ 221, 166, 236, 200, 194, 231, 252, 143, 237, 102, 219, 148, 133, 237, 185,
+ 202, 55, 175, 218, 202, 166, 44, 107, 211, 69, 158, 52, 158, 185, 151,
+ 45, 91, 181, 224, 42, 31, 52, 83, 99, 243, 108, 254, 167, 107, 79,
+ 249, 139, 237, 102, 219, 148, 45, 123, 228, 169, 57, 154, 243, 190, 77,
+ 217, 241, 28, 31, 77, 226, 143, 237, 212, 108, 223, 176, 236, 157, 191,
+ 150, 218, 224, 53, 232, 234, 169, 41, 122, 118, 171, 77, 89, 114, 205,
+ 103, 188, 121, 156, 173, 180, 127, 7, 254, 200, 247, 11, 155, 106, 131,
+ 215, 255, 131, 147, 40, 179, 205, 152, 78, 123, 112, 17, 250, 102, 59,
+ 6, 169, 7, 159, 34, 63, 155, 178, 206, 241, 5, 52, 41, 239, 108,
+ 205, 98, 219, 192, 57, 58, 244, 116, 153, 13, 94, 205, 225, 94, 198,
+ 46, 241, 219, 108, 218, 189, 126, 162, 168, 93, 153, 130, 150, 217, 208,
+ 174, 59, 252, 155, 193, 182, 76, 33, 148, 141, 92, 55, 221, 161, 13,
+ 251, 178, 242, 171, 126, 53, 216, 63, 131, 171, 150, 253, 189, 161, 92,
+ 151, 41, 54, 120, 43, 34, 210, 13, 246, 125, 251, 227, 229, 60, 67,
+ 192, 31, 147, 237, 240, 244, 14, 252, 230, 214, 254, 200, 16, 229, 167,
+ 87, 219, 62, 199, 16, 248, 217, 148, 93, 94, 252, 189, 97, 251, 47,
+ 41, 54, 101, 187, 38, 124, 239, 192, 111, 234, 250, 227, 134, 160, 239,
+ 91, 58, 240, 179, 215, 151, 254, 97, 75, 29, 240, 94, 196, 124, 228,
+ 192, 15, 241, 186, 196, 183, 204, 178, 231, 103, 175, 207, 216, 174, 214,
+ 14, 175, 207, 154, 178, 134, 170, 211, 51, 108, 117, 119, 113, 29, 187,
+ 50, 5, 140, 105, 178, 193, 126, 222, 254, 57, 213, 215, 97, 222, 194,
+ 70, 70, 26, 110, 167, 151, 176, 193, 155, 241, 224, 126, 150, 125, 153,
+ 247, 138, 67, 89, 246, 180, 233, 31, 207, 207, 178, 111, 3, 172, 157,
+ 33, 226, 94, 7, 27, 249, 206, 69, 123, 24, 82, 147, 251, 216, 172,
+ 243, 119, 63, 8, 113, 40, 211, 251, 116, 118, 224, 167, 153, 253, 81,
+ 184, 125, 89, 218, 184, 205, 234, 176, 61, 99, 109, 202, 98, 15, 252,
+ 170, 182, 31, 231, 221, 19, 182, 171, 87, 68, 36, 216, 200, 162, 79,
+ 156, 27, 110, 175, 247, 98, 187, 54, 101, 26, 191, 236, 3, 35, 214,
+ 77, 183, 157, 243, 142, 61, 194, 237, 203, 180, 126, 115, 212, 197, 42,
+ 182, 176, 41, 203, 105, 244, 181, 131, 44, 217, 147, 22, 168, 67, 70,
+ 214, 176, 29, 171, 138, 113, 225, 246, 235, 3, 219, 181, 47, 83, 86,
+ 172, 203, 219, 203, 231, 187, 170, 56, 111, 191, 86, 197, 50, 103, 180,
+ 54, 243, 118, 164, 205, 94, 71, 126, 93, 182, 56, 242, 131, 50, 207,
+ 21, 17, 182, 54, 118, 228, 16, 7, 218, 78, 126, 90, 7, 90, 177,
+ 204, 134, 246, 75, 101, 172, 131, 44, 88, 118, 114, 18, 111, 59, 31,
+ 239, 108, 117, 160, 21, 101, 206, 178, 127, 14, 57, 195, 195, 236, 3,
+ 235, 137, 190, 205, 151, 148, 37, 229, 8, 17, 158, 237, 248, 146, 138,
+ 112, 71, 132, 103, 62, 190, 164, 2, 220, 81, 24, 159, 234, 17, 225,
+ 89, 98, 117, 82, 11, 74, 136, 240, 60, 167, 22, 241, 19, 225, 106,
+ 194, 147, 184, 90, 34, 92, 27, 202, 107, 137, 56, 181, 133, 167, 122,
+ 230, 242, 74, 128, 83, 93, 44, 175, 68, 106, 8, 111, 9, 198, 242,
+ 58, 128, 83, 91, 44, 199, 39, 116, 149, 44, 112, 125, 82, 67, 196,
+ 169, 11, 56, 117, 196, 242, 186, 164, 42, 220, 153, 203, 235, 1, 92,
+ 215, 130, 95, 15, 40, 104, 57, 62, 113, 52, 195, 85, 224, 174, 178,
+ 136, 227, 79, 26, 144, 134, 98, 127, 253, 133, 39, 122, 230, 56, 164,
+ 49, 244, 173, 129, 136, 239, 79, 154, 146, 198, 34, 220, 68, 120, 238,
+ 71, 105, 3, 72, 83, 17, 63, 0, 106, 154, 138, 56, 1, 36, 144,
+ 52, 17, 224, 18, 0, 5, 139, 48, 62, 87, 108, 36, 188, 99, 92,
+ 41, 60, 45, 12, 38, 129, 2, 220, 147, 52, 35, 106, 18, 46, 242,
+ 84, 147, 48, 17, 174, 6, 48, 79, 194, 68, 62, 60, 9, 21, 225,
+ 106, 128, 143, 120, 102, 88, 3, 229, 188, 72, 171, 33, 33, 36, 84,
+ 44, 111, 9, 176, 70, 44, 143, 0, 184, 165, 5, 110, 65, 66, 68,
+ 156, 86, 0, 71, 136, 229, 173, 72, 115, 210, 194, 194, 31, 159, 246,
+ 81, 184, 57, 220, 153, 101, 104, 75, 90, 147, 54, 226, 88, 181, 37,
+ 237, 224, 206, 220, 151, 206, 164, 19, 137, 18, 203, 59, 19, 45, 233,
+ 36, 246, 87, 11, 26, 213, 73, 228, 211, 145, 180, 39, 29, 68, 156,
+ 142, 164, 27, 220, 153, 203, 59, 147, 46, 68, 43, 242, 233, 10, 53,
+ 90, 81, 158, 174, 128, 211, 81, 108, 87, 73, 138, 9, 239, 226, 68,
+ 90, 124, 166, 93, 76, 164, 85, 146, 194, 112, 103, 110, 171, 176, 240,
+ 76, 219, 140, 95, 132, 248, 136, 48, 62, 123, 45, 36, 188, 155, 84,
+ 41, 60, 65, 46, 36, 224, 34, 255, 18, 194, 147, 114, 90, 238, 37,
+ 228, 63, 34, 92, 18, 224, 18, 34, 142, 66, 140, 245, 148, 164, 160,
+ 144, 67, 168, 16, 96, 79, 82, 134, 152, 191, 201, 165, 20, 158, 212,
+ 151, 17, 225, 72, 160, 45, 40, 188, 41, 21, 249, 20, 128, 114, 79,
+ 177, 188, 20, 148, 151, 20, 225, 130, 80, 94, 192, 82, 94, 70, 248,
+ 166, 186, 82, 120, 166, 94, 90, 224, 139, 50, 227, 186, 244, 45, 99,
+ 142, 73, 27, 136, 235, 210, 241, 185, 136, 109, 153, 201, 238, 143, 198,
+ 230, 210, 57, 138, 121, 227, 195, 189, 229, 243, 150, 207, 91, 62, 111,
+ 249, 188, 229, 243, 150, 207, 91, 62, 111, 249, 188, 229, 243, 150, 207,
+ 91, 62, 111, 249, 188, 229, 243, 150, 207, 91, 62, 111, 249, 188, 229,
+ 243, 191, 132, 143, 212, 111, 245, 254, 111, 231, 243, 118, 222, 255, 127,
+ 228, 67, 115, 4, 48, 47, 128, 230, 8, 224, 59, 214, 48, 103, 64,
+ 151, 104, 126, 182, 31, 213, 26, 223, 239, 70, 95, 111, 220, 204, 33,
+ 71, 64, 229, 226, 187, 201, 1, 192, 183, 78, 128, 143, 240, 138, 84,
+ 227, 192, 142, 94, 198, 7, 237, 189, 234, 144, 158, 146, 121, 2, 103,
+ 224, 10, 225, 204, 188, 151, 181, 141, 48, 36, 92, 95, 139, 121, 1,
+ 153, 138, 196, 233, 154, 187, 15, 234, 105, 140, 123, 207, 56, 228, 8,
+ 40, 152, 94, 89, 126, 67, 182, 177, 245, 187, 201, 57, 30, 226, 251,
+ 84, 149, 32, 3, 180, 223, 72, 108, 167, 195, 198, 233, 134, 221, 101,
+ 234, 24, 106, 142, 86, 242, 234, 39, 222, 207, 151, 167, 16, 211, 207,
+ 156, 191, 161, 107, 169, 97, 134, 209, 85, 7, 240, 225, 5, 54, 94,
+ 214, 78, 34, 166, 105, 191, 63, 10, 63, 60, 38, 214, 80, 3, 240,
+ 30, 112, 3, 158, 223, 76, 81, 152, 254, 60, 119, 196, 208, 254, 244,
+ 117, 67, 187, 216, 123, 234, 121, 109, 21, 75, 86, 62, 35, 166, 91,
+ 23, 46, 27, 102, 241, 223, 26, 10, 247, 111, 200, 39, 60, 46, 253,
+ 119, 206, 20, 98, 154, 161, 254, 219, 176, 40, 108, 167, 128, 55, 251,
+ 73, 175, 103, 75, 128, 246, 94, 124, 5, 227, 173, 141, 255, 24, 102,
+ 76, 250, 65, 93, 61, 55, 253, 21, 129, 118, 75, 173, 43, 101, 252,
+ 114, 122, 33, 227, 135, 35, 235, 242, 145, 59, 159, 13, 91, 82, 132,
+ 152, 234, 61, 44, 102, 60, 221, 95, 105, 68, 188, 201, 161, 91, 230,
+ 47, 121, 69, 76, 85, 207, 55, 53, 206, 158, 90, 194, 168, 91, 90,
+ 153, 247, 206, 217, 60, 190, 153, 74, 97, 106, 24, 94, 213, 24, 31,
+ 84, 194, 120, 123, 108, 16, 223, 161, 114, 244, 7, 87, 47, 17, 83,
+ 185, 254, 213, 141, 199, 122, 61, 51, 196, 71, 29, 81, 255, 241, 115,
+ 183, 247, 198, 189, 32, 166, 217, 217, 26, 129, 54, 197, 84, 67, 125,
+ 238, 215, 244, 73, 231, 255, 84, 88, 218, 189, 153, 89, 87, 29, 220,
+ 186, 248, 226, 185, 62, 214, 126, 140, 250, 106, 166, 250, 158, 199, 55,
+ 164, 164, 158, 152, 126, 129, 113, 209, 194, 184, 244, 215, 44, 83, 207,
+ 47, 84, 236, 214, 231, 211, 136, 165, 221, 230, 11, 23, 133, 143, 185,
+ 243, 193, 248, 117, 23, 21, 166, 1, 91, 226, 13, 207, 135, 151, 50,
+ 206, 219, 145, 193, 55, 189, 186, 117, 124, 55, 63, 133, 73, 85, 239,
+ 70, 86, 169, 65, 127, 24, 106, 173, 89, 192, 95, 120, 53, 75, 249,
+ 199, 20, 133, 233, 157, 6, 93, 213, 149, 55, 191, 52, 248, 70, 207,
+ 230, 163, 148, 127, 78, 233, 175, 32, 166, 202, 123, 86, 242, 61, 111,
+ 221, 53, 204, 239, 59, 154, 31, 86, 170, 208, 227, 170, 48, 126, 126,
+ 223, 127, 206, 127, 80, 253, 39, 3, 231, 49, 134, 15, 46, 193, 229,
+ 126, 63, 153, 152, 38, 141, 249, 73, 29, 215, 53, 35, 107, 157, 223,
+ 42, 190, 65, 241, 90, 127, 158, 159, 172, 48, 205, 76, 175, 148, 85,
+ 201, 191, 180, 177, 94, 253, 61, 124, 56, 41, 54, 239, 228, 9, 133,
+ 233, 175, 42, 105, 106, 44, 219, 123, 55, 133, 47, 224, 179, 87, 191,
+ 255, 41, 49, 69, 102, 252, 200, 79, 25, 95, 214, 184, 179, 121, 123,
+ 126, 72, 248, 226, 212, 95, 238, 43, 76, 21, 14, 63, 231, 3, 215,
+ 43, 132, 178, 145, 222, 15, 114, 207, 129, 124, 91, 23, 255, 196, 79,
+ 168, 30, 97, 184, 117, 62, 133, 255, 165, 200, 236, 63, 195, 65, 150,
+ 176, 167, 243, 213, 63, 21, 169, 199, 123, 167, 110, 231, 15, 150, 56,
+ 153, 123, 17, 218, 93, 61, 244, 10, 255, 207, 186, 245, 89, 229, 160,
+ 31, 83, 189, 130, 254, 250, 10, 240, 252, 85, 31, 242, 77, 46, 174,
+ 225, 251, 244, 220, 196, 15, 171, 181, 162, 224, 31, 19, 137, 233, 82,
+ 216, 51, 126, 205, 79, 83, 248, 169, 189, 151, 241, 171, 154, 15, 233,
+ 61, 186, 131, 194, 20, 30, 179, 90, 125, 243, 153, 143, 81, 55, 99,
+ 61, 223, 250, 217, 168, 247, 134, 249, 17, 211, 177, 31, 15, 243, 117,
+ 39, 251, 24, 145, 159, 230, 214, 236, 232, 37, 233, 196, 148, 116, 225,
+ 59, 254, 220, 225, 39, 134, 87, 218, 15, 248, 93, 53, 54, 223, 49,
+ 76, 32, 166, 86, 157, 55, 240, 43, 119, 55, 50, 68, 116, 201, 228,
+ 163, 203, 85, 186, 249, 23, 232, 233, 211, 144, 84, 222, 72, 78, 134,
+ 125, 165, 63, 193, 231, 60, 27, 124, 181, 193, 251, 196, 116, 254, 199,
+ 157, 252, 198, 35, 65, 134, 47, 238, 204, 228, 239, 87, 223, 92, 239,
+ 219, 121, 196, 212, 125, 210, 167, 252, 238, 161, 235, 213, 158, 119, 143,
+ 242, 47, 94, 252, 94, 240, 40, 62, 215, 175, 252, 55, 223, 174, 228,
+ 169, 3, 89, 176, 190, 30, 20, 41, 255, 240, 42, 140, 193, 142, 163,
+ 87, 120, 255, 250, 233, 134, 6, 7, 134, 243, 247, 254, 220, 118, 101,
+ 238, 68, 51, 237, 94, 160, 93, 191, 184, 35, 191, 224, 236, 136, 178,
+ 229, 230, 153, 219, 189, 10, 237, 246, 25, 217, 134, 175, 127, 243, 7,
+ 238, 231, 105, 102, 249, 86, 128, 124, 103, 230, 132, 242, 59, 95, 164,
+ 120, 181, 214, 91, 251, 177, 119, 84, 5, 126, 87, 161, 93, 5, 63,
+ 210, 91, 251, 59, 103, 163, 47, 223, 254, 69, 165, 30, 177, 58, 24,
+ 103, 113, 92, 254, 172, 25, 197, 207, 243, 153, 59, 173, 96, 89, 98,
+ 154, 35, 206, 111, 242, 199, 60, 95, 170, 112, 165, 121, 67, 154, 40,
+ 76, 23, 135, 204, 16, 116, 237, 72, 217, 113, 188, 239, 149, 51, 19,
+ 180, 127, 40, 76, 81, 220, 71, 198, 73, 171, 187, 25, 134, 213, 237,
+ 208, 120, 208, 201, 99, 115, 241, 81, 109, 159, 3, 223, 26, 230, 15,
+ 255, 152, 111, 182, 45, 84, 29, 243, 234, 94, 85, 229, 12, 98, 186,
+ 204, 253, 144, 53, 126, 110, 45, 205, 182, 244, 202, 124, 173, 87, 183,
+ 91, 205, 90, 72, 76, 189, 7, 220, 205, 122, 39, 129, 215, 212, 78,
+ 155, 192, 239, 250, 235, 218, 128, 185, 95, 41, 76, 29, 58, 22, 54,
+ 46, 184, 81, 86, 19, 152, 51, 144, 79, 184, 249, 115, 212, 131, 213,
+ 196, 116, 113, 97, 35, 227, 205, 140, 177, 252, 135, 165, 14, 170, 253,
+ 188, 13, 229, 43, 131, 78, 86, 107, 81, 193, 184, 239, 230, 112, 94,
+ 147, 229, 167, 110, 121, 34, 240, 102, 242, 2, 98, 90, 49, 166, 149,
+ 113, 218, 218, 52, 126, 147, 166, 126, 227, 162, 30, 253, 174, 205, 154,
+ 78, 76, 235, 199, 61, 51, 140, 223, 245, 55, 255, 217, 129, 106, 234,
+ 34, 79, 155, 54, 59, 48, 79, 97, 218, 149, 18, 105, 248, 231, 85,
+ 3, 141, 102, 67, 5, 222, 244, 244, 188, 246, 239, 85, 196, 244, 235,
+ 165, 9, 70, 227, 190, 247, 249, 210, 215, 10, 241, 223, 158, 253, 89,
+ 91, 183, 151, 194, 52, 240, 183, 84, 227, 167, 75, 170, 102, 197, 53,
+ 201, 80, 87, 221, 245, 135, 103, 197, 56, 98, 250, 99, 238, 44, 99,
+ 175, 182, 93, 13, 151, 126, 251, 73, 221, 240, 116, 120, 243, 53, 67,
+ 21, 166, 232, 238, 195, 141, 187, 103, 86, 51, 212, 10, 216, 170, 158,
+ 123, 157, 203, 104, 50, 136, 152, 174, 169, 206, 25, 98, 215, 220, 53,
+ 240, 71, 9, 63, 227, 105, 207, 45, 189, 160, 172, 224, 163, 43, 89,
+ 39, 238, 237, 53, 84, 250, 214, 139, 191, 204, 169, 183, 182, 27, 76,
+ 76, 95, 20, 219, 160, 238, 188, 112, 131, 161, 67, 216, 123, 252, 189,
+ 95, 14, 236, 234, 57, 132, 152, 122, 53, 40, 173, 217, 186, 231, 47,
+ 67, 129, 152, 72, 62, 160, 82, 139, 207, 174, 118, 6, 29, 63, 219,
+ 65, 115, 209, 235, 99, 195, 247, 191, 38, 243, 103, 251, 94, 57, 215,
+ 188, 139, 194, 164, 245, 111, 165, 249, 167, 243, 44, 245, 63, 239, 69,
+ 242, 127, 13, 234, 18, 124, 95, 77, 76, 241, 254, 158, 198, 65, 39,
+ 215, 170, 251, 93, 94, 174, 142, 244, 218, 217, 38, 97, 56, 49, 141,
+ 187, 178, 216, 208, 185, 73, 81, 62, 173, 104, 49, 254, 175, 156, 175,
+ 155, 252, 51, 26, 198, 111, 203, 111, 89, 131, 122, 127, 198, 171, 166,
+ 151, 226, 199, 95, 240, 141, 24, 29, 67, 76, 103, 134, 22, 208, 156,
+ 57, 52, 149, 111, 177, 216, 135, 175, 173, 25, 217, 219, 212, 138, 152,
+ 116, 223, 133, 240, 37, 55, 110, 230, 91, 13, 232, 205, 235, 185, 101,
+ 81, 199, 1, 47, 179, 96, 117, 227, 209, 131, 151, 213, 159, 156, 248,
+ 71, 61, 191, 225, 229, 218, 199, 18, 136, 233, 235, 29, 61, 141, 83,
+ 127, 190, 175, 222, 186, 172, 58, 191, 225, 69, 159, 234, 79, 97, 125,
+ 24, 150, 119, 52, 250, 110, 218, 125, 96, 85, 223, 65, 252, 242, 23,
+ 237, 31, 47, 2, 91, 124, 247, 115, 63, 227, 205, 150, 17, 134, 67,
+ 195, 159, 168, 67, 174, 15, 248, 173, 24, 224, 45, 57, 86, 210, 56,
+ 38, 100, 16, 159, 102, 122, 21, 124, 179, 243, 201, 33, 132, 40, 76,
+ 133, 115, 139, 241, 219, 58, 84, 54, 28, 120, 178, 156, 127, 244, 98,
+ 225, 171, 7, 64, 27, 116, 244, 104, 214, 77, 159, 62, 134, 196, 164,
+ 0, 222, 227, 228, 38, 226, 147, 76, 76, 169, 93, 27, 241, 165, 135,
+ 29, 82, 151, 58, 59, 147, 127, 247, 229, 156, 82, 19, 192, 30, 36,
+ 214, 249, 52, 235, 121, 250, 65, 53, 246, 173, 242, 181, 237, 222, 181,
+ 97, 93, 214, 105, 241, 53, 191, 224, 231, 139, 134, 18, 47, 218, 243,
+ 199, 239, 87, 202, 232, 9, 253, 184, 54, 56, 198, 48, 216, 56, 67,
+ 240, 71, 37, 189, 35, 142, 222, 31, 67, 76, 105, 223, 4, 25, 98,
+ 75, 149, 53, 220, 30, 58, 67, 125, 84, 83, 46, 247, 208, 39, 196,
+ 244, 153, 88, 86, 199, 103, 24, 191, 161, 228, 222, 194, 13, 160, 141,
+ 89, 97, 51, 14, 236, 228, 19, 179, 208, 71, 29, 242, 212, 151, 138,
+ 131, 245, 187, 88, 57, 208, 48, 161, 77, 143, 3, 177, 153, 69, 248,
+ 197, 47, 61, 42, 150, 5, 61, 173, 85, 225, 67, 67, 165, 86, 213,
+ 12, 131, 170, 39, 241, 127, 148, 53, 229, 122, 65, 217, 203, 27, 95,
+ 25, 50, 79, 206, 54, 140, 159, 90, 146, 255, 161, 232, 185, 203, 219,
+ 97, 157, 55, 241, 87, 26, 191, 155, 58, 255, 192, 200, 9, 185, 234,
+ 65, 164, 155, 223, 226, 247, 136, 169, 118, 165, 127, 12, 7, 251, 111,
+ 53, 204, 45, 26, 198, 183, 63, 231, 113, 112, 242, 80, 98, 242, 233,
+ 252, 139, 193, 247, 66, 57, 195, 170, 228, 100, 62, 226, 207, 31, 61,
+ 50, 160, 221, 171, 233, 91, 13, 13, 11, 21, 86, 183, 225, 130, 248,
+ 211, 207, 118, 6, 158, 31, 75, 76, 47, 238, 4, 26, 7, 175, 52,
+ 24, 180, 101, 62, 82, 119, 202, 30, 191, 143, 68, 19, 211, 189, 43,
+ 77, 140, 223, 116, 59, 103, 80, 15, 215, 102, 100, 28, 152, 241, 9,
+ 142, 115, 135, 139, 75, 248, 230, 93, 11, 24, 111, 220, 110, 180, 195,
+ 227, 215, 158, 51, 176, 236, 179, 211, 227, 140, 125, 219, 181, 49, 116,
+ 44, 52, 59, 120, 224, 141, 130, 248, 179, 18, 166, 247, 215, 95, 52,
+ 244, 217, 227, 109, 108, 190, 97, 94, 102, 199, 71, 201, 122, 44, 235,
+ 152, 194, 25, 126, 30, 114, 215, 48, 117, 220, 141, 204, 150, 117, 244,
+ 179, 144, 182, 114, 218, 2, 245, 156, 178, 71, 12, 31, 23, 44, 190,
+ 163, 210, 237, 146, 211, 132, 212, 141, 19, 149, 52, 97, 137, 5, 141,
+ 31, 94, 237, 177, 163, 127, 80, 143, 15, 17, 175, 74, 183, 94, 154,
+ 98, 191, 45, 54, 180, 237, 213, 110, 199, 165, 241, 37, 126, 64, 188,
+ 117, 105, 81, 154, 207, 78, 125, 169, 206, 92, 89, 126, 71, 145, 164,
+ 138, 205, 17, 239, 69, 143, 103, 134, 109, 193, 74, 254, 213, 185, 144,
+ 224, 114, 37, 46, 77, 65, 188, 247, 154, 109, 52, 180, 57, 18, 205,
+ 175, 107, 250, 85, 208, 149, 29, 61, 49, 155, 210, 212, 195, 207, 71,
+ 179, 123, 209, 90, 126, 96, 173, 207, 50, 181, 161, 35, 199, 32, 173,
+ 178, 85, 51, 254, 230, 153, 43, 252, 135, 127, 108, 205, 200, 245, 50,
+ 164, 96, 217, 148, 39, 181, 13, 47, 134, 27, 249, 79, 7, 13, 11,
+ 78, 59, 252, 19, 190, 118, 206, 244, 104, 239, 74, 99, 90, 137, 213,
+ 89, 239, 206, 141, 107, 60, 79, 223, 234, 33, 226, 233, 47, 77, 53,
+ 246, 110, 48, 154, 31, 82, 184, 119, 227, 46, 155, 46, 234, 176, 236,
+ 185, 117, 76, 179, 132, 49, 253, 12, 116, 8, 198, 190, 177, 121, 236,
+ 13, 56, 246, 245, 63, 36, 166, 162, 48, 71, 101, 97, 142, 86, 39,
+ 39, 27, 112, 142, 162, 166, 42, 44, 115, 249, 81, 209, 48, 3, 206,
+ 229, 244, 229, 230, 57, 63, 14, 115, 30, 55, 33, 55, 11, 231, 124,
+ 4, 216, 201, 87, 160, 27, 25, 160, 27, 147, 166, 150, 52, 160, 110,
+ 116, 158, 5, 122, 0, 58, 84, 1, 116, 40, 166, 122, 146, 1, 117,
+ 232, 41, 216, 251, 37, 160, 107, 9, 160, 107, 195, 51, 139, 24, 80,
+ 215, 238, 64, 153, 30, 116, 50, 29, 116, 178, 206, 104, 165, 1, 117,
+ 114, 41, 180, 187, 6, 116, 119, 40, 232, 110, 3, 159, 97, 6, 212,
+ 221, 115, 83, 173, 58, 158, 59, 116, 70, 22, 234, 184, 122, 20, 49,
+ 221, 128, 181, 48, 8, 214, 66, 93, 160, 197, 181, 80, 124, 62, 196,
+ 67, 176, 102, 82, 97, 205, 84, 126, 209, 222, 128, 107, 230, 235, 21,
+ 196, 148, 12, 107, 235, 21, 172, 173, 106, 211, 75, 25, 42, 193, 218,
+ 186, 4, 54, 118, 30, 172, 193, 242, 176, 6, 203, 156, 157, 105, 192,
+ 53, 56, 7, 218, 104, 12, 107, 245, 26, 172, 213, 241, 73, 1, 6,
+ 92, 171, 15, 231, 18, 147, 39, 172, 233, 205, 176, 166, 15, 62, 89,
+ 110, 192, 53, 93, 84, 111, 182, 7, 215, 193, 30, 100, 13, 127, 146,
+ 133, 246, 224, 239, 153, 196, 100, 4, 187, 225, 13, 118, 99, 89, 223,
+ 65, 6, 180, 27, 35, 1, 111, 19, 216, 151, 25, 96, 95, 54, 46,
+ 171, 110, 64, 251, 226, 53, 211, 108, 135, 142, 131, 29, 154, 123, 226,
+ 159, 44, 180, 67, 45, 192, 7, 244, 7, 123, 85, 10, 236, 85, 235,
+ 1, 189, 13, 104, 175, 154, 131, 204, 103, 193, 174, 157, 5, 187, 166,
+ 89, 236, 99, 64, 187, 198, 237, 39, 166, 26, 96, 255, 6, 155, 237,
+ 159, 1, 237, 223, 199, 128, 55, 30, 236, 164, 214, 108, 39, 13, 104,
+ 39, 189, 83, 205, 246, 116, 8, 216, 211, 222, 151, 151, 103, 161, 61,
+ 77, 93, 76, 4, 187, 251, 28, 236, 174, 231, 251, 145, 6, 180, 187,
+ 197, 15, 154, 237, 243, 5, 176, 207, 215, 126, 77, 54, 160, 125, 62,
+ 158, 174, 176, 216, 241, 82, 49, 145, 6, 180, 227, 85, 183, 17, 211,
+ 106, 176, 247, 157, 192, 222, 119, 15, 123, 207, 128, 246, 254, 235, 149,
+ 196, 84, 24, 252, 194, 41, 240, 11, 213, 190, 245, 50, 160, 95, 216,
+ 189, 202, 236, 63, 226, 192, 127, 180, 60, 74, 12, 232, 63, 190, 2,
+ 63, 72, 253, 76, 213, 128, 173, 89, 232, 103, 78, 173, 54, 251, 163,
+ 30, 224, 143, 178, 127, 251, 41, 11, 253, 209, 187, 203, 205, 126, 43,
+ 13, 252, 86, 191, 38, 25, 89, 232, 183, 110, 46, 33, 166, 28, 240,
+ 111, 7, 193, 191, 249, 92, 43, 100, 64, 255, 118, 113, 163, 194, 180,
+ 7, 252, 224, 83, 240, 131, 33, 27, 42, 24, 208, 15, 22, 27, 108,
+ 245, 151, 51, 15, 84, 203, 66, 127, 217, 42, 73, 97, 241, 181, 254,
+ 89, 126, 89, 232, 107, 231, 37, 152, 125, 242, 111, 224, 147, 83, 74,
+ 29, 204, 66, 159, 124, 29, 244, 175, 163, 232, 187, 235, 229, 128, 110,
+ 130, 239, 46, 10, 62, 175, 63, 248, 248, 190, 224, 227, 171, 165, 77,
+ 48, 160, 143, 31, 219, 83, 97, 250, 9, 98, 129, 9, 16, 11, 108,
+ 78, 175, 108, 192, 88, 96, 210, 72, 107, 204, 80, 119, 91, 104, 22,
+ 198, 12, 185, 96, 255, 126, 132, 120, 227, 25, 196, 27, 167, 202, 142,
+ 51, 96, 188, 145, 94, 26, 214, 165, 24, 151, 76, 254, 152, 55, 96,
+ 92, 178, 234, 164, 194, 212, 28, 226, 151, 27, 16, 191, 252, 83, 51,
+ 202, 128, 241, 203, 179, 219, 196, 116, 92, 140, 115, 22, 111, 244, 53,
+ 96, 156, 179, 12, 214, 106, 178, 24, 15, 29, 27, 85, 193, 128, 241,
+ 80, 18, 230, 148, 65, 220, 180, 12, 226, 166, 11, 115, 66, 13, 24,
+ 55, 237, 195, 188, 73, 136, 175, 84, 220, 201, 176, 129, 35, 219, 24,
+ 48, 190, 170, 14, 54, 187, 27, 196, 97, 89, 16, 135, 109, 90, 220,
+ 209, 128, 113, 216, 237, 36, 98, 218, 14, 241, 90, 3, 136, 215, 154,
+ 31, 24, 110, 192, 120, 109, 44, 172, 213, 30, 16, 215, 213, 129, 184,
+ 238, 208, 222, 51, 6, 140, 235, 170, 194, 26, 68, 90, 35, 208, 122,
+ 221, 61, 106, 192, 248, 47, 4, 226, 176, 239, 33, 78, 92, 15, 113,
+ 226, 87, 119, 102, 26, 48, 78, 12, 4, 126, 143, 161, 93, 13, 180,
+ 187, 89, 127, 194, 128, 241, 228, 57, 88, 91, 17, 162, 124, 109, 186,
+ 100, 26, 48, 238, 44, 1, 122, 159, 8, 253, 248, 30, 250, 81, 160,
+ 235, 7, 6, 140, 79, 91, 206, 38, 166, 163, 208, 223, 58, 208, 223,
+ 42, 209, 179, 13, 24, 199, 14, 239, 66, 44, 227, 18, 51, 99, 189,
+ 1, 227, 221, 229, 191, 192, 152, 66, 92, 252, 5, 196, 197, 51, 122,
+ 47, 51, 96, 92, 252, 241, 14, 133, 169, 1, 196, 207, 205, 32, 126,
+ 238, 219, 115, 147, 1, 227, 231, 50, 208, 143, 21, 16, 103, 63, 132,
+ 56, 187, 18, 240, 195, 56, 187, 23, 172, 233, 230, 16, 143, 231, 64,
+ 60, 94, 40, 117, 187, 1, 227, 241, 186, 211, 20, 166, 45, 16, 183,
+ 143, 131, 184, 253, 239, 243, 41, 6, 140, 219, 15, 3, 94, 37, 49,
+ 190, 63, 210, 188, 189, 1, 227, 251, 6, 48, 6, 116, 31, 128, 101,
+ 184, 15, 168, 86, 76, 97, 186, 5, 251, 133, 138, 48, 151, 223, 220,
+ 77, 49, 224, 126, 33, 178, 32, 248, 115, 152, 95, 44, 107, 84, 127,
+ 143, 1, 247, 21, 77, 155, 42, 76, 9, 176, 255, 208, 193, 254, 99,
+ 131, 223, 42, 3, 238, 63, 234, 67, 187, 85, 96, 159, 50, 11, 246,
+ 41, 69, 61, 198, 24, 112, 159, 226, 15, 250, 87, 1, 246, 51, 221,
+ 96, 63, 179, 162, 239, 104, 3, 238, 103, 174, 130, 44, 90, 216, 247,
+ 84, 128, 125, 79, 101, 232, 7, 238, 123, 214, 189, 132, 181, 15, 251,
+ 163, 146, 176, 63, 170, 183, 102, 129, 1, 247, 71, 101, 64, 62, 29,
+ 236, 163, 80, 215, 82, 119, 100, 24, 112, 31, 181, 229, 23, 235, 62,
+ 175, 251, 194, 69, 7, 112, 191, 213, 191, 142, 194, 178, 47, 139, 209,
+ 44, 203, 194, 125, 217, 192, 201, 214, 253, 91, 242, 87, 51, 179, 112,
+ 255, 246, 39, 179, 191, 124, 144, 89, 55, 11, 247, 121, 99, 31, 88,
+ 247, 131, 179, 77, 53, 178, 112, 63, 88, 191, 132, 66, 216, 55, 30,
+ 135, 125, 99, 82, 212, 145, 44, 220, 55, 126, 232, 97, 221, 231, 221,
+ 29, 27, 100, 192, 253, 101, 213, 90, 196, 164, 18, 247, 161, 131, 150,
+ 86, 54, 224, 62, 244, 196, 175, 10, 203, 126, 117, 222, 164, 31, 178,
+ 112, 191, 58, 156, 179, 182, 59, 127, 100, 93, 3, 238, 107, 135, 63,
+ 36, 150, 253, 239, 135, 128, 39, 236, 127, 167, 90, 247, 201, 157, 99,
+ 239, 101, 225, 62, 121, 56, 216, 216, 219, 98, 63, 138, 245, 111, 104,
+ 192, 253, 180, 10, 240, 112, 223, 221, 14, 246, 221, 93, 1, 15, 247,
+ 221, 49, 5, 192, 207, 192, 254, 252, 16, 236, 207, 235, 131, 175, 192,
+ 253, 121, 69, 189, 121, 92, 58, 195, 184, 36, 87, 29, 96, 192, 125,
+ 124, 58, 232, 105, 71, 216, 239, 239, 132, 253, 62, 250, 35, 220, 239,
+ 15, 211, 155, 115, 56, 87, 21, 194, 119, 150, 245, 244, 242, 23, 207,
+ 5, 114, 131, 99, 189, 44, 239, 93, 99, 224, 4, 6, 14, 96, 224,
+ 220, 32, 6, 159, 129, 19, 24, 56, 128, 129, 115, 3, 25, 124, 6,
+ 78, 96, 224, 0, 6, 206, 13, 96, 240, 25, 56, 129, 129, 3, 24,
+ 56, 167, 145, 21, 78, 99, 96, 29, 3, 171, 24, 56, 199, 159, 193,
+ 103, 96, 29, 3, 171, 24, 56, 167, 33, 131, 207, 192, 58, 6, 86,
+ 49, 112, 78, 3, 6, 159, 129, 117, 12, 172, 98, 224, 156, 250, 12,
+ 62, 3, 235, 24, 88, 197, 192, 57, 245, 24, 124, 6, 214, 49, 176,
+ 138, 129, 115, 234, 50, 248, 12, 172, 99, 96, 21, 3, 231, 212, 97,
+ 240, 25, 88, 199, 192, 42, 6, 206, 169, 205, 224, 51, 176, 142, 129,
+ 85, 12, 156, 83, 139, 193, 103, 96, 29, 3, 171, 24, 56, 167, 38,
+ 131, 207, 192, 58, 6, 86, 49, 112, 78, 13, 6, 159, 129, 117, 12,
+ 172, 4, 152, 30, 226, 25, 171, 91, 225, 4, 6, 14, 168, 206, 232,
+ 100, 53, 70, 39, 25, 88, 87, 205, 138, 175, 100, 224, 108, 63, 43,
+ 78, 42, 3, 231, 164, 48, 178, 49, 176, 142, 129, 85, 12, 156, 61,
+ 197, 202, 51, 117, 138, 181, 92, 195, 148, 231, 78, 182, 194, 233, 147,
+ 25, 158, 76, 185, 146, 129, 179, 223, 103, 100, 99, 96, 45, 3, 43,
+ 25, 56, 251, 61, 6, 159, 129, 181, 12, 172, 100, 96, 227, 36, 102,
+ 60, 25, 88, 197, 192, 217, 19, 173, 176, 158, 129, 3, 24, 56, 119,
+ 2, 51, 86, 19, 172, 229, 90, 6, 38, 12, 108, 28, 111, 197, 215,
+ 51, 176, 134, 129, 115, 199, 89, 241, 211, 24, 88, 203, 192, 202, 113,
+ 76, 223, 199, 50, 125, 103, 96, 45, 3, 147, 177, 204, 248, 39, 91,
+ 97, 29, 3, 43, 25, 56, 59, 137, 225, 201, 192, 90, 6, 86, 50,
+ 112, 118, 34, 131, 207, 192, 90, 6, 86, 50, 176, 113, 12, 51, 254,
+ 12, 28, 48, 134, 209, 195, 4, 70, 175, 24, 88, 195, 192, 57, 163,
+ 153, 241, 103, 96, 29, 3, 171, 24, 56, 39, 158, 193, 103, 96, 109,
+ 60, 51, 95, 12, 108, 28, 197, 204, 23, 3, 107, 24, 56, 119, 36,
+ 51, 95, 12, 172, 101, 96, 229, 72, 102, 172, 70, 48, 99, 197, 192,
+ 90, 6, 86, 50, 112, 246, 112, 6, 159, 129, 181, 12, 172, 100, 224,
+ 236, 56, 6, 159, 129, 181, 12, 172, 100, 224, 236, 88, 6, 159, 129,
+ 181, 12, 172, 100, 224, 236, 97, 12, 62, 3, 107, 25, 88, 201, 192,
+ 217, 67, 25, 124, 6, 214, 50, 176, 146, 129, 179, 99, 24, 124, 6,
+ 214, 50, 176, 146, 129, 179, 135, 48, 248, 12, 172, 101, 96, 37, 3,
+ 103, 15, 102, 240, 25, 88, 203, 192, 74, 6, 206, 30, 196, 224, 51,
+ 176, 150, 129, 149, 12, 156, 29, 205, 224, 51, 176, 150, 129, 149, 12,
+ 156, 173, 99, 116, 76, 199, 232, 57, 83, 158, 83, 156, 209, 91, 6,
+ 214, 49, 176, 138, 129, 115, 138, 49, 248, 12, 172, 99, 96, 101, 49,
+ 70, 207, 139, 50, 235, 145, 129, 3, 138, 50, 122, 238, 195, 248, 23,
+ 6, 166, 239, 176, 198, 24, 173, 161, 248, 124, 167, 144, 248, 220, 139,
+ 254, 206, 133, 143, 24, 183, 185, 170, 79, 144, 169, 15, 144, 169, 199,
+ 152, 207, 101, 251, 50, 245, 9, 76, 125, 17, 177, 158, 254, 78, 134,
+ 143, 24, 47, 186, 170, 199, 24, 210, 85, 125, 58, 83, 95, 84, 172,
+ 167, 191, 131, 225, 35, 198, 154, 174, 234, 3, 100, 234, 49, 38, 117,
+ 85, 159, 30, 224, 90, 190, 132, 0, 153, 241, 151, 169, 199, 24, 215,
+ 85, 251, 105, 76, 125, 25, 177, 158, 254, 14, 132, 143, 24, 11, 187,
+ 170, 87, 49, 245, 165, 196, 122, 250, 59, 22, 62, 98, 204, 236, 170,
+ 62, 141, 169, 47, 65, 159, 203, 86, 97, 218, 151, 169, 87, 249, 187,
+ 150, 15, 99, 112, 151, 237, 203, 212, 235, 26, 202, 180, 47, 83, 143,
+ 49, 189, 171, 250, 52, 153, 122, 29, 83, 95, 156, 202, 167, 99, 218,
+ 151, 169, 199, 61, 130, 203, 254, 203, 212, 235, 234, 203, 244, 95, 166,
+ 30, 247, 28, 46, 251, 95, 207, 181, 252, 58, 153, 122, 149, 76, 61,
+ 238, 97, 92, 213, 167, 201, 212, 235, 234, 202, 244, 95, 166, 30, 247,
+ 68, 46, 251, 95, 71, 102, 252, 101, 234, 85, 117, 100, 244, 191, 182,
+ 235, 250, 52, 166, 94, 33, 214, 211, 223, 177, 242, 17, 247, 98, 180,
+ 158, 163, 242, 251, 51, 237, 203, 212, 227, 158, 205, 85, 125, 154, 76,
+ 189, 174, 150, 107, 249, 84, 50, 245, 184, 7, 116, 85, 159, 86, 83,
+ 166, 125, 153, 122, 149, 12, 127, 220, 83, 186, 108, 95, 166, 94, 231,
+ 162, 222, 87, 220, 143, 54, 20, 235, 60, 169, 255, 40, 243, 88, 33,
+ 254, 214, 46, 79, 127, 83, 204, 87, 220, 175, 58, 195, 45, 32, 226,
+ 210, 223, 255, 242, 21, 247, 179, 20, 183, 32, 237, 247, 96, 138, 171,
+ 183, 224, 250, 136, 251, 93, 42, 35, 139, 107, 241, 129, 213, 92, 215,
+ 167, 51, 245, 246, 252, 125, 197, 189, 50, 149, 197, 131, 250, 48, 232,
+ 151, 248, 155, 10, 60, 253, 221, 51, 95, 113, 47, 237, 206, 120, 248,
+ 136, 123, 109, 218, 46, 139, 75, 235, 83, 253, 164, 229, 242, 17, 247,
+ 228, 174, 234, 211, 82, 100, 230, 86, 166, 94, 149, 226, 122, 238, 113,
+ 143, 239, 108, 92, 196, 56, 209, 134, 87, 234, 20, 215, 188, 52, 83,
+ 220, 155, 111, 95, 241, 220, 192, 29, 61, 242, 17, 207, 21, 92, 206,
+ 237, 100, 247, 117, 82, 57, 217, 149, 140, 182, 237, 226, 89, 5, 109,
+ 215, 139, 218, 189, 186, 204, 120, 200, 212, 107, 101, 234, 149, 50, 245,
+ 120, 246, 225, 178, 125, 153, 122, 173, 76, 189, 146, 169, 103, 231, 222,
+ 178, 214, 39, 217, 143, 43, 145, 180, 11, 9, 147, 220, 183, 33, 170,
+ 60, 224, 226, 89, 141, 59, 250, 233, 43, 158, 229, 184, 139, 27, 48,
+ 209, 125, 61, 192, 179, 32, 87, 122, 159, 54, 193, 253, 254, 104, 39,
+ 184, 175, 171, 100, 130, 251, 246, 19, 207, 159, 92, 217, 71, 189, 76,
+ 189, 102, 188, 235, 53, 134, 103, 87, 238, 218, 207, 180, 113, 121, 24,
+ 15, 6, 151, 109, 87, 164, 83, 179, 182, 84, 57, 206, 181, 173, 196,
+ 243, 50, 151, 182, 120, 172, 107, 91, 169, 29, 235, 122, 158, 201, 88,
+ 247, 245, 11, 207, 226, 220, 29, 3, 93, 30, 112, 149, 201, 238, 173,
+ 73, 31, 241, 172, 79, 106, 125, 251, 136, 231, 127, 180, 222, 155, 246,
+ 215, 143, 25, 15, 153, 122, 165, 76, 61, 158, 29, 186, 170, 79, 149,
+ 169, 215, 202, 212, 43, 93, 212, 251, 138, 103, 145, 238, 172, 113, 95,
+ 241, 172, 210, 93, 127, 20, 48, 198, 245, 90, 193, 243, 77, 119, 215,
+ 120, 106, 130, 251, 62, 83, 147, 224, 190, 175, 198, 243, 83, 151, 49,
+ 163, 76, 189, 78, 166, 94, 53, 90, 38, 174, 137, 151, 137, 107, 226,
+ 165, 215, 170, 175, 120, 110, 235, 238, 154, 32, 241, 238, 217, 38, 31,
+ 241, 220, 215, 149, 92, 250, 81, 50, 118, 210, 69, 189, 175, 120, 102,
+ 236, 238, 124, 166, 141, 116, 95, 79, 180, 35, 221, 143, 73, 149, 35,
+ 93, 207, 29, 158, 83, 187, 170, 79, 149, 169, 215, 202, 212, 43, 153,
+ 122, 154, 39, 79, 127, 87, 217, 71, 60, 247, 118, 85, 159, 58, 92,
+ 166, 125, 153, 122, 165, 12, 127, 60, 71, 119, 217, 190, 76, 189, 86,
+ 166, 94, 201, 212, 151, 165, 58, 48, 133, 105, 63, 214, 117, 125, 42,
+ 83, 95, 154, 234, 179, 7, 211, 190, 76, 189, 146, 169, 47, 73, 117,
+ 165, 0, 211, 254, 48, 215, 245, 169, 50, 245, 90, 166, 94, 73, 245,
+ 218, 139, 105, 95, 166, 30, 159, 27, 184, 170, 79, 149, 169, 215, 202,
+ 212, 43, 135, 202, 244, 63, 70, 166, 255, 50, 245, 218, 24, 153, 241,
+ 151, 169, 199, 231, 26, 46, 251, 47, 83, 175, 29, 226, 90, 62, 165,
+ 76, 61, 62, 39, 113, 217, 127, 153, 122, 237, 96, 153, 254, 203, 212,
+ 227, 115, 23, 151, 250, 63, 72, 166, 125, 153, 122, 229, 32, 153, 246,
+ 163, 93, 215, 167, 70, 187, 150, 79, 43, 83, 175, 100, 234, 139, 209,
+ 125, 87, 33, 166, 125, 157, 181, 190, 48, 165, 47, 198, 236, 99, 116,
+ 86, 91, 207, 214, 251, 80, 91, 83, 132, 241, 71, 12, 47, 103, 245,
+ 248, 124, 201, 149, 44, 105, 50, 245, 58, 153, 122, 149, 76, 61, 62,
+ 175, 114, 37, 95, 154, 76, 189, 206, 69, 189, 175, 248, 172, 203, 157,
+ 177, 242, 21, 159, 133, 185, 139, 155, 80, 212, 253, 57, 8, 40, 42,
+ 61, 159, 62, 226, 243, 53, 87, 245, 233, 46, 234, 119, 195, 160, 226,
+ 119, 186, 234, 89, 190, 171, 229, 41, 252, 138, 172, 146, 252, 202, 97,
+ 4, 99, 254, 29, 174, 231, 156, 167, 240, 203, 72, 248, 219, 162, 89,
+ 28, 254, 154, 40, 190, 37, 172, 6, 217, 196, 121, 1, 71, 140, 141,
+ 253, 72, 48, 87, 72, 120, 243, 24, 174, 153, 222, 0, 23, 17, 198,
+ 83, 69, 198, 113, 69, 128, 74, 208, 91, 146, 200, 121, 11, 111, 45,
+ 195, 223, 86, 106, 6, 112, 97, 241, 183, 170, 18, 184, 194, 164, 16,
+ 224, 40, 137, 63, 201, 5, 254, 222, 194, 155, 205, 148, 164, 63, 135,
+ 191, 93, 138, 111, 60, 43, 65, 126, 226, 10, 0, 84, 20, 164, 168,
+ 76, 118, 112, 120, 18, 94, 12, 100, 42, 79, 238, 3, 255, 194, 194,
+ 249, 67, 73, 50, 4, 96, 47, 33, 46, 82, 145, 30, 28, 254, 174,
+ 87, 17, 225, 76, 59, 25, 224, 34, 66, 121, 77, 18, 192, 149, 18,
+ 222, 187, 87, 26, 254, 109, 229, 240, 253, 125, 126, 112, 223, 128, 188,
+ 199, 149, 22, 222, 217, 87, 6, 248, 108, 225, 240, 173, 126, 213, 224,
+ 222, 151, 60, 224, 240, 109, 127, 213, 133, 119, 172, 157, 231, 202, 8,
+ 239, 243, 195, 223, 252, 186, 203, 85, 20, 222, 200, 135, 191, 195, 53,
+ 158, 43, 43, 252, 242, 22, 254, 206, 215, 11, 14, 223, 223, 87, 75,
+ 248, 13, 175, 95, 184, 202, 194, 187, 255, 106, 0, 230, 90, 174, 10,
+ 64, 181, 133, 223, 240, 122, 197, 213, 36, 117, 0, 174, 5, 178, 61,
+ 224, 202, 9, 191, 250, 133, 227, 208, 147, 195, 95, 12, 43, 41, 244,
+ 101, 60, 135, 191, 58, 22, 32, 142, 97, 9, 225, 215, 182, 202, 65,
+ 43, 127, 115, 37, 197, 119, 231, 149, 34, 99, 128, 182, 17, 17, 206,
+ 60, 96, 108, 125, 1, 246, 23, 224, 166, 128, 163, 18, 206, 226, 85,
+ 192, 179, 36, 208, 169, 4, 158, 9, 0, 227, 155, 247, 8, 148, 140,
+ 225, 240, 55, 205, 252, 133, 49, 233, 198, 225, 59, 215, 240, 55, 189,
+ 170, 144, 94, 192, 7, 127, 229, 171, 60, 200, 115, 3, 198, 161, 33,
+ 140, 77, 5, 248, 247, 152, 195, 183, 178, 225, 27, 2, 43, 2, 126,
+ 25, 24, 131, 250, 112, 87, 10, 100, 171, 0, 159, 245, 161, 180, 60,
+ 201, 132, 49, 169, 47, 188, 81, 176, 60, 249, 13, 198, 164, 146, 240,
+ 214, 193, 82, 32, 115, 37, 224, 92, 23, 238, 74, 145, 37, 28, 190,
+ 139, 176, 46, 180, 90, 5, 230, 40, 152, 132, 136, 239, 16, 28, 207,
+ 5, 9, 111, 216, 107, 33, 232, 94, 19, 248, 108, 46, 200, 63, 22,
+ 224, 230, 194, 251, 4, 91, 129, 108, 65, 226, 187, 5, 75, 193, 92,
+ 7, 9, 191, 17, 102, 150, 63, 158, 132, 139, 239, 4, 28, 15, 112,
+ 160, 240, 222, 64, 13, 73, 2, 56, 148, 140, 22, 96, 44, 15, 19,
+ 222, 9, 168, 129, 177, 10, 21, 126, 105, 204, 60, 230, 248, 59, 98,
+ 136, 83, 13, 198, 39, 8, 228, 9, 22, 248, 196, 0, 76, 223, 15,
+ 24, 196, 53, 5, 74, 243, 59, 248, 198, 1, 220, 65, 104, 183, 52,
+ 41, 5, 112, 71, 241, 93, 126, 221, 56, 124, 43, 97, 71, 17, 14,
+ 35, 157, 68, 56, 24, 96, 181, 248, 238, 191, 193, 28, 190, 209, 80,
+ 45, 242, 236, 96, 121, 39, 224, 16, 78, 77, 162, 44, 56, 67, 8,
+ 132, 244, 66, 223, 199, 3, 172, 17, 222, 105, 168, 130, 190, 224, 219,
+ 22, 155, 8, 115, 215, 148, 195, 55, 41, 6, 9, 176, 134, 11, 1,
+ 57, 155, 8, 56, 201, 0, 55, 17, 198, 83, 5, 125, 137, 35, 157,
+ 5, 57, 107, 0, 159, 102, 0, 55, 23, 198, 42, 136, 171, 10, 154,
+ 135, 111, 53, 68, 61, 172, 13, 122, 24, 33, 252, 198, 217, 5, 40,
+ 143, 36, 194, 111, 70, 195, 56, 215, 33, 221, 197, 247, 33, 6, 115,
+ 248, 75, 123, 189, 73, 47, 128, 167, 192, 122, 44, 78, 122, 194, 93,
+ 121, 192, 239, 5, 159, 125, 200, 59, 130, 77, 232, 1, 245, 239, 144,
+ 190, 0, 31, 16, 172, 72, 47, 210, 3, 52, 189, 15, 192, 61, 0,
+ 191, 56, 104, 194, 26, 174, 53, 72, 211, 65, 208, 195, 158, 0, 199,
+ 137, 99, 24, 13, 112, 7, 210, 79, 104, 171, 52, 140, 73, 39, 17,
+ 14, 226, 240, 77, 138, 253, 196, 241, 124, 135, 12, 32, 253, 5, 254,
+ 205, 184, 54, 228, 93, 104, 23, 203, 203, 1, 237, 187, 226, 123, 24,
+ 99, 160, 188, 15, 233, 38, 192, 17, 0, 119, 35, 109, 5, 24, 127,
+ 148, 62, 138, 12, 20, 224, 182, 0, 247, 23, 222, 207, 168, 129, 126,
+ 13, 134, 145, 29, 40, 244, 183, 49, 192, 3, 137, 78, 128, 135, 114,
+ 131, 0, 86, 11, 112, 51, 128, 117, 34, 206, 24, 46, 10, 104, 7,
+ 8, 124, 146, 1, 30, 96, 145, 243, 93, 128, 204, 229, 99, 1, 110,
+ 45, 150, 107, 184, 190, 132, 23, 223, 59, 89, 19, 224, 254, 226, 187,
+ 41, 85, 92, 31, 144, 121, 128, 48, 110, 58, 78, 11, 50, 247, 196,
+ 92, 8, 104, 75, 11, 50, 155, 251, 213, 18, 240, 181, 66, 57, 234,
+ 103, 95, 224, 162, 21, 251, 165, 6, 105, 204, 239, 151, 84, 114, 93,
+ 97, 182, 218, 139, 58, 223, 21, 86, 84, 59, 97, 108, 91, 113, 248,
+ 118, 207, 118, 162, 62, 84, 1, 168, 174, 176, 94, 148, 92, 93, 210,
+ 149, 116, 17, 236, 225, 80, 174, 37, 204, 111, 23, 145, 182, 46, 64,
+ 221, 133, 242, 198, 48, 239, 117, 5, 184, 36, 233, 202, 5, 138, 239,
+ 226, 172, 1, 115, 52, 8, 224, 64, 129, 103, 36, 232, 149, 249, 221,
+ 151, 42, 82, 3, 224, 54, 100, 184, 0, 183, 225, 240, 183, 240, 70,
+ 137, 246, 167, 13, 64, 230, 242, 106, 220, 40, 225, 55, 242, 204, 118,
+ 108, 20, 64, 35, 69, 24, 127, 55, 111, 132, 5, 30, 33, 150, 39,
+ 114, 145, 36, 86, 44, 31, 15, 240, 8, 177, 47, 1, 220, 48, 40,
+ 143, 20, 230, 46, 16, 224, 72, 225, 93, 156, 26, 88, 59, 195, 0,
+ 138, 16, 231, 113, 24, 64, 67, 133, 242, 161, 92, 4, 244, 36, 90,
+ 228, 31, 1, 208, 80, 145, 127, 52, 148, 183, 20, 199, 39, 26, 160,
+ 24, 81, 231, 99, 0, 214, 8, 112, 45, 128, 129, 179, 0, 15, 129,
+ 177, 162, 239, 229, 28, 7, 176, 86, 156, 83, 45, 215, 69, 120, 51,
+ 167, 89, 31, 186, 0, 164, 21, 203, 187, 65, 185, 121, 94, 26, 115,
+ 248, 118, 207, 182, 226, 188, 159, 34, 39, 201, 9, 114, 28, 96, 3,
+ 119, 154, 156, 2, 232, 24, 192, 47, 185, 227, 228, 27, 114, 84, 128,
+ 47, 114, 39, 200, 17, 184, 59, 14, 99, 222, 157, 251, 6, 224, 67,
+ 130, 111, 29, 202, 29, 38, 7, 5, 184, 52, 248, 214, 195, 196, 40,
+ 252, 216, 38, 218, 132, 131, 0, 239, 23, 125, 235, 17, 98, 16, 224,
+ 72, 50, 12, 224, 253, 2, 62, 218, 180, 67, 0, 27, 201, 97, 193,
+ 183, 158, 32, 89, 128, 117, 4, 240, 215, 114, 39, 201, 1, 184, 59,
+ 1, 243, 158, 193, 29, 3, 9, 12, 112, 87, 142, 92, 6, 217, 142,
+ 1, 116, 0, 116, 230, 31, 224, 255, 141, 216, 110, 32, 192, 71, 225,
+ 14, 219, 237, 202, 25, 64, 130, 253, 130, 206, 140, 1, 248, 168, 32,
+ 79, 117, 208, 231, 61, 100, 55, 249, 154, 108, 2, 252, 129, 92, 38,
+ 124, 126, 77, 50, 192, 203, 221, 227, 118, 147, 93, 228, 43, 184, 243,
+ 5, 249, 51, 224, 243, 43, 178, 29, 116, 236, 5, 183, 29, 160, 141,
+ 100, 27, 200, 179, 151, 219, 69, 118, 2, 252, 21, 192, 73, 220, 54,
+ 128, 190, 36, 91, 1, 254, 147, 219, 73, 210, 1, 222, 8, 240, 3,
+ 46, 157, 108, 33, 235, 225, 78, 73, 118, 113, 91, 225, 115, 61, 217,
+ 0, 50, 247, 231, 182, 144, 205, 228, 11, 184, 83, 146, 39, 220, 6,
+ 248, 252, 130, 172, 3, 217, 94, 112, 59, 64, 134, 76, 97, 28, 122,
+ 114, 251, 200, 94, 178, 67, 232, 203, 120, 128, 87, 145, 189, 226, 24,
+ 238, 131, 210, 213, 112, 95, 151, 60, 228, 246, 194, 231, 106, 225, 57,
+ 116, 50, 208, 102, 10, 48, 234, 76, 38, 249, 84, 132, 7, 3, 206,
+ 30, 224, 106, 246, 173, 123, 1, 50, 243, 76, 0, 120, 53, 96, 161,
+ 77, 78, 6, 248, 83, 192, 194, 49, 233, 6, 99, 242, 41, 249, 12,
+ 198, 165, 10, 89, 15, 124, 50, 0, 254, 20, 230, 55, 17, 198, 97,
+ 59, 73, 131, 59, 244, 173, 187, 225, 51, 13, 198, 168, 34, 89, 7,
+ 227, 144, 70, 62, 135, 177, 64, 31, 186, 29, 198, 230, 115, 184, 47,
+ 69, 190, 135, 49, 217, 74, 214, 192, 29, 250, 220, 157, 240, 185, 6,
+ 198, 165, 60, 200, 156, 14, 208, 90, 24, 151, 242, 224, 91, 183, 194,
+ 120, 172, 133, 251, 42, 96, 111, 87, 144, 229, 100, 145, 184, 198, 87,
+ 146, 197, 96, 255, 151, 128, 156, 6, 110, 25, 64, 139, 133, 49, 25,
+ 11, 240, 82, 193, 47, 128, 61, 0, 156, 165, 100, 153, 208, 247, 64,
+ 128, 151, 192, 157, 89, 254, 120, 242, 9, 249, 216, 226, 91, 63, 22,
+ 236, 0, 250, 208, 120, 240, 154, 11, 5, 120, 28, 192, 11, 1, 203,
+ 92, 190, 16, 56, 46, 21, 199, 103, 33, 224, 52, 23, 99, 188, 149,
+ 100, 133, 40, 79, 19, 128, 23, 9, 50, 40, 201, 32, 110, 41, 153,
+ 46, 240, 193, 121, 95, 10, 237, 206, 16, 236, 79, 27, 128, 103, 144,
+ 233, 162, 253, 95, 8, 208, 39, 34, 252, 9, 192, 211, 4, 120, 40,
+ 192, 211, 72, 170, 0, 55, 5, 56, 85, 148, 115, 16, 55, 3, 202,
+ 205, 180, 129, 92, 42, 192, 83, 69, 156, 33, 224, 89, 23, 136, 54,
+ 97, 8, 64, 243, 69, 120, 5, 244, 124, 185, 48, 119, 131, 1, 94,
+ 41, 140, 67, 57, 176, 153, 139, 0, 90, 44, 218, 255, 69, 128, 177,
+ 204, 226, 91, 151, 128, 71, 197, 49, 76, 226, 150, 64, 15, 59, 139,
+ 250, 191, 153, 124, 72, 230, 130, 246, 161, 30, 126, 1, 208, 60, 208,
+ 67, 37, 217, 9, 229, 179, 160, 6, 105, 187, 115, 235, 160, 244, 125,
+ 81, 254, 83, 100, 34, 153, 0, 118, 65, 73, 126, 135, 245, 56, 129,
+ 76, 18, 214, 221, 78, 110, 34, 25, 71, 198, 195, 61, 218, 132, 247,
+ 200, 88, 184, 155, 8, 240, 21, 88, 155, 239, 1, 116, 10, 44, 252,
+ 231, 0, 31, 0, 252, 247, 32, 18, 235, 193, 125, 0, 99, 181, 68,
+ 208, 195, 158, 0, 47, 1, 239, 138, 99, 216, 24, 224, 100, 97, 60,
+ 209, 167, 204, 0, 120, 154, 56, 62, 211, 0, 158, 42, 142, 231, 56,
+ 224, 159, 68, 18, 1, 62, 203, 205, 129, 86, 199, 136, 190, 242, 3,
+ 50, 71, 132, 155, 64, 249, 100, 168, 65, 184, 36, 192, 179, 225, 14,
+ 225, 238, 220, 2, 146, 32, 242, 41, 7, 240, 84, 224, 99, 182, 189,
+ 131, 161, 220, 60, 206, 209, 0, 235, 72, 130, 0, 7, 129, 31, 73,
+ 21, 225, 97, 0, 39, 136, 62, 55, 129, 155, 10, 237, 39, 9, 124,
+ 198, 0, 156, 12, 119, 102, 57, 199, 0, 148, 44, 250, 214, 49, 0,
+ 125, 32, 250, 190, 177, 48, 115, 11, 68, 223, 58, 22, 160, 36, 209,
+ 198, 142, 135, 145, 74, 4, 169, 209, 183, 166, 192, 232, 140, 23, 246,
+ 26, 195, 0, 30, 47, 202, 92, 26, 240, 39, 145, 20, 209, 38, 140,
+ 5, 104, 190, 216, 175, 84, 144, 63, 65, 244, 221, 83, 200, 76, 152,
+ 49, 179, 206, 79, 1, 104, 173, 48, 182, 101, 193, 206, 204, 2, 75,
+ 99, 214, 135, 45, 80, 58, 75, 88, 47, 26, 110, 45, 209, 147, 41,
+ 130, 61, 12, 230, 62, 2, 248, 125, 145, 118, 45, 64, 122, 161, 60,
+ 26, 230, 253, 125, 145, 79, 15, 240, 173, 31, 11, 122, 91, 13, 230,
+ 104, 16, 172, 168, 84, 129, 167, 18, 244, 106, 142, 208, 71, 216, 161,
+ 0, 60, 28, 238, 16, 198, 49, 31, 5, 163, 110, 182, 63, 115, 160,
+ 220, 236, 103, 85, 224, 79, 103, 138, 229, 73, 0, 143, 132, 59, 179,
+ 189, 154, 9, 126, 115, 150, 88, 62, 19, 202, 71, 136, 227, 252, 33,
+ 64, 177, 98, 92, 253, 33, 96, 152, 203, 117, 224, 55, 63, 20, 202,
+ 53, 2, 60, 87, 208, 85, 179, 159, 157, 71, 230, 138, 243, 56, 12,
+ 60, 232, 60, 161, 60, 136, 155, 7, 254, 244, 125, 145, 255, 60, 40,
+ 143, 22, 249, 71, 147, 143, 196, 242, 49, 0, 199, 192, 29, 194, 221,
+ 192, 159, 206, 23, 225, 234, 0, 15, 17, 215, 93, 0, 140, 85, 138,
+ 48, 62, 184, 246, 63, 130, 210, 20, 209, 135, 234, 97, 182, 166, 136,
+ 250, 160, 135, 210, 201, 98, 249, 100, 232, 161, 185, 60, 26, 224, 217,
+ 66, 127, 113, 222, 113, 47, 171, 237, 99, 126, 47, 73, 3, 113, 47,
+ 219, 35, 219, 135, 191, 83, 234, 138, 250, 246, 170, 130, 188, 166, 250,
+ 56, 245, 47, 125, 139, 243, 7, 114, 38, 170, 219, 205, 244, 227, 171,
+ 103, 123, 58, 188, 87, 165, 111, 141, 196, 109, 154, 119, 97, 126, 188,
+ 197, 28, 214, 28, 243, 123, 71, 188, 19, 158, 170, 189, 62, 251, 65,
+ 189, 111, 252, 63, 234, 85, 234, 36, 11, 63, 202, 223, 158, 207, 181,
+ 99, 135, 131, 51, 134, 58, 242, 161, 116, 148, 207, 31, 190, 207, 213,
+ 23, 103, 122, 168, 87, 87, 40, 200, 215, 126, 252, 56, 220, 158, 79,
+ 142, 49, 49, 252, 187, 254, 142, 124, 104, 63, 40, 63, 74, 127, 209,
+ 163, 8, 95, 246, 234, 125, 7, 62, 195, 66, 199, 108, 217, 209, 217,
+ 145, 15, 165, 235, 244, 179, 39, 223, 163, 194, 14, 11, 189, 212, 123,
+ 103, 198, 183, 121, 190, 190, 80, 168, 35, 31, 21, 255, 68, 189, 169,
+ 100, 11, 11, 159, 39, 253, 30, 170, 15, 180, 189, 46, 201, 103, 243,
+ 157, 42, 189, 219, 246, 147, 230, 67, 233, 11, 55, 253, 75, 221, 125,
+ 237, 213, 48, 41, 62, 157, 210, 59, 235, 250, 86, 116, 228, 67, 233,
+ 169, 60, 114, 124, 118, 252, 101, 232, 221, 113, 157, 35, 31, 58, 30,
+ 148, 15, 29, 47, 41, 62, 77, 187, 133, 111, 91, 244, 141, 60, 31,
+ 250, 41, 197, 103, 94, 193, 96, 92, 18, 14, 124, 40, 29, 29, 39,
+ 218, 47, 90, 110, 207, 39, 154, 43, 172, 63, 99, 146, 214, 31, 42,
+ 23, 237, 23, 213, 39, 123, 62, 107, 35, 158, 236, 248, 106, 171, 35,
+ 31, 186, 142, 236, 245, 81, 106, 93, 24, 234, 248, 29, 209, 47, 113,
+ 228, 99, 191, 174, 168, 60, 116, 125, 216, 243, 121, 118, 106, 109, 100,
+ 191, 207, 165, 215, 169, 253, 186, 167, 252, 237, 249, 212, 186, 248, 77,
+ 248, 186, 165, 242, 250, 35, 55, 239, 134, 203, 71, 186, 53, 233, 43,
+ 205, 199, 190, 63, 82, 124, 106, 221, 156, 218, 119, 72, 47, 249, 117,
+ 42, 183, 190, 98, 31, 174, 236, 51, 108, 157, 52, 31, 74, 47, 39,
+ 207, 114, 175, 172, 193, 129, 233, 142, 124, 218, 107, 34, 248, 150, 229,
+ 127, 84, 55, 105, 216, 145, 95, 218, 224, 123, 245, 228, 175, 135, 243,
+ 225, 245, 139, 242, 23, 39, 246, 225, 167, 124, 228, 227, 192, 199, 207,
+ 39, 174, 227, 38, 39, 246, 240, 210, 135, 157, 249, 162, 241, 103, 212,
+ 61, 43, 36, 241, 155, 15, 22, 229, 41, 31, 202, 215, 65, 15, 189,
+ 163, 63, 82, 55, 119, 178, 190, 196, 118, 41, 253, 254, 103, 49, 124,
+ 220, 253, 178, 252, 173, 167, 61, 249, 42, 145, 37, 28, 228, 121, 126,
+ 233, 3, 239, 27, 19, 29, 249, 80, 57, 198, 70, 143, 225, 91, 175,
+ 168, 108, 225, 67, 249, 218, 243, 25, 210, 97, 230, 169, 63, 223, 113,
+ 228, 67, 233, 127, 184, 210, 134, 55, 190, 104, 202, 155, 72, 8, 31,
+ 183, 174, 129, 133, 159, 61, 159, 193, 189, 87, 152, 222, 27, 224, 200,
+ 135, 202, 111, 161, 19, 249, 92, 248, 179, 60, 191, 58, 171, 162, 3,
+ 159, 49, 223, 222, 202, 78, 27, 233, 200, 135, 202, 177, 174, 91, 8,
+ 159, 54, 163, 37, 63, 250, 165, 138, 255, 126, 65, 11, 11, 63, 123,
+ 62, 123, 123, 174, 121, 126, 203, 137, 31, 180, 180, 43, 210, 81, 62,
+ 59, 203, 253, 173, 62, 118, 59, 192, 129, 79, 210, 249, 211, 57, 139,
+ 147, 29, 249, 80, 124, 74, 127, 169, 109, 69, 94, 169, 142, 228, 203,
+ 254, 252, 143, 186, 236, 242, 222, 14, 124, 170, 63, 24, 86, 182, 231,
+ 100, 71, 62, 180, 63, 170, 209, 225, 124, 207, 236, 70, 22, 62, 150,
+ 254, 217, 253, 121, 61, 106, 216, 238, 119, 39, 246, 135, 182, 75, 233,
+ 199, 76, 109, 206, 119, 154, 208, 9, 214, 68, 57, 184, 146, 29, 248,
+ 188, 91, 254, 120, 205, 21, 227, 85, 142, 254, 75, 148, 227, 78, 147,
+ 62, 124, 239, 123, 181, 44, 124, 40, 95, 123, 62, 131, 78, 240, 39,
+ 223, 119, 178, 46, 154, 79, 142, 224, 55, 246, 220, 174, 166, 235, 131,
+ 174, 7, 169, 117, 218, 174, 238, 209, 249, 5, 234, 59, 242, 89, 80,
+ 220, 159, 223, 119, 108, 166, 154, 242, 27, 214, 176, 33, 191, 179, 250,
+ 30, 73, 62, 205, 158, 255, 211, 186, 240, 8, 105, 62, 148, 126, 74,
+ 219, 250, 124, 177, 98, 41, 146, 124, 38, 110, 57, 167, 59, 94, 82,
+ 154, 15, 165, 167, 114, 209, 79, 123, 62, 141, 94, 249, 232, 235, 58,
+ 241, 131, 84, 14, 74, 39, 39, 79, 244, 239, 217, 173, 186, 44, 145,
+ 30, 103, 251, 241, 150, 126, 239, 158, 183, 83, 191, 76, 233, 40, 31,
+ 185, 249, 138, 244, 187, 181, 104, 192, 33, 233, 126, 81, 122, 106, 103,
+ 165, 248, 4, 85, 174, 62, 232, 112, 39, 249, 241, 145, 147, 167, 105,
+ 209, 242, 81, 109, 98, 228, 229, 161, 252, 164, 248, 248, 63, 141, 236,
+ 52, 97, 185, 52, 31, 123, 191, 33, 197, 231, 167, 162, 197, 6, 55,
+ 116, 225, 119, 236, 237, 189, 148, 191, 248, 231, 110, 118, 143, 178, 107,
+ 164, 231, 203, 222, 127, 81, 251, 111, 207, 231, 232, 131, 239, 23, 213,
+ 219, 39, 237, 47, 236, 253, 14, 181, 255, 246, 124, 206, 135, 146, 75,
+ 223, 47, 150, 246, 95, 246, 246, 94, 202, 239, 108, 223, 165, 87, 205,
+ 91, 41, 237, 47, 236, 237, 180, 148, 223, 249, 35, 115, 194, 159, 191,
+ 46, 151, 246, 95, 246, 126, 199, 226, 207, 236, 254, 166, 183, 62, 90,
+ 249, 155, 101, 210, 126, 199, 222, 95, 80, 187, 237, 160, 207, 173, 22,
+ 148, 46, 182, 88, 218, 239, 216, 251, 13, 41, 255, 245, 106, 111, 47,
+ 18, 190, 72, 218, 239, 216, 219, 123, 41, 127, 145, 120, 166, 119, 163,
+ 161, 139, 164, 253, 142, 189, 255, 162, 246, 223, 158, 79, 133, 71, 135,
+ 234, 100, 79, 112, 228, 3, 35, 13, 250, 159, 3, 235, 32, 22, 62,
+ 113, 61, 12, 128, 207, 162, 146, 239, 123, 29, 91, 177, 65, 175, 9,
+ 95, 40, 157, 240, 73, 1, 124, 21, 208, 143, 129, 79, 13, 196, 133,
+ 189, 145, 30, 118, 106, 209, 240, 217, 206, 97, 93, 108, 40, 126, 237,
+ 159, 160, 169, 97, 78, 248, 180, 2, 252, 37, 106, 74, 103, 229, 227,
+ 92, 158, 33, 63, 44, 127, 183, 245, 78, 79, 7, 62, 29, 123, 84,
+ 10, 127, 244, 176, 52, 95, 120, 196, 199, 225, 159, 172, 56, 160, 206,
+ 76, 46, 164, 62, 84, 247, 160, 228, 122, 47, 243, 121, 96, 161, 30,
+ 61, 29, 199, 167, 199, 186, 225, 234, 114, 227, 11, 240, 148, 159, 28,
+ 159, 31, 42, 154, 78, 165, 142, 145, 230, 67, 233, 107, 77, 13, 84,
+ 95, 11, 146, 182, 63, 87, 43, 182, 93, 20, 196, 59, 155, 47, 21,
+ 62, 14, 9, 251, 182, 88, 184, 250, 206, 229, 146, 225, 159, 254, 241,
+ 121, 120, 210, 59, 211, 37, 227, 240, 135, 155, 126, 184, 118, 173, 191,
+ 52, 31, 216, 209, 169, 89, 126, 82, 124, 148, 235, 79, 108, 45, 82,
+ 223, 91, 146, 207, 71, 239, 235, 195, 72, 95, 250, 219, 147, 177, 146,
+ 253, 42, 189, 84, 23, 217, 177, 66, 9, 73, 62, 180, 63, 86, 126,
+ 206, 249, 76, 79, 171, 81, 119, 89, 7, 199, 126, 81, 58, 58, 206,
+ 116, 254, 165, 248, 124, 233, 83, 37, 238, 215, 182, 210, 124, 172, 244,
+ 174, 251, 165, 188, 244, 219, 68, 252, 21, 51, 233, 117, 65, 215, 23,
+ 93, 111, 206, 249, 124, 91, 228, 85, 133, 137, 211, 43, 185, 224, 67,
+ 215, 5, 229, 231, 156, 79, 195, 154, 35, 124, 26, 205, 114, 228, 67,
+ 199, 133, 246, 175, 97, 31, 15, 245, 233, 47, 102, 74, 251, 193, 18,
+ 239, 212, 27, 53, 158, 72, 242, 169, 188, 178, 159, 186, 243, 177, 109,
+ 178, 250, 156, 214, 122, 122, 67, 117, 180, 52, 31, 42, 7, 229, 39,
+ 197, 167, 125, 249, 23, 126, 198, 9, 210, 243, 69, 245, 71, 174, 95,
+ 253, 111, 92, 125, 118, 241, 125, 71, 62, 148, 126, 151, 190, 135, 122,
+ 111, 110, 140, 236, 248, 132, 127, 215, 185, 70, 210, 24, 105, 62, 67,
+ 186, 232, 212, 77, 179, 238, 88, 248, 73, 241, 41, 126, 229, 253, 125,
+ 159, 196, 72, 243, 161, 235, 147, 242, 147, 148, 167, 232, 173, 50, 209,
+ 78, 246, 41, 116, 92, 105, 127, 228, 228, 185, 227, 251, 176, 89, 191,
+ 4, 71, 62, 180, 253, 122, 95, 111, 83, 207, 106, 63, 74, 150, 79,
+ 205, 63, 190, 76, 111, 50, 200, 145, 143, 241, 159, 250, 252, 174, 226,
+ 59, 212, 3, 162, 138, 241, 37, 247, 13, 81, 95, 56, 95, 134, 159,
+ 113, 63, 82, 218, 174, 86, 48, 126, 98, 10, 147, 230, 19, 21, 89,
+ 157, 31, 223, 234, 140, 133, 159, 20, 159, 11, 85, 230, 45, 15, 110,
+ 227, 200, 103, 211, 80, 141, 122, 254, 174, 40, 254, 231, 207, 138, 169,
+ 23, 118, 234, 101, 177, 247, 82, 124, 244, 229, 91, 108, 14, 122, 87,
+ 154, 15, 165, 167, 118, 95, 138, 79, 71, 223, 97, 39, 215, 140, 113,
+ 102, 159, 233, 250, 166, 235, 157, 250, 69, 231, 124, 22, 93, 234, 20,
+ 221, 105, 167, 210, 5, 31, 74, 239, 218, 191, 119, 184, 60, 126, 84,
+ 202, 9, 95, 7, 62, 19, 115, 167, 171, 79, 148, 188, 162, 14, 191,
+ 223, 82, 221, 165, 231, 69, 217, 245, 94, 190, 251, 146, 222, 113, 245,
+ 28, 251, 69, 233, 40, 31, 57, 251, 188, 185, 89, 193, 196, 143, 148,
+ 206, 198, 199, 188, 47, 166, 251, 219, 153, 199, 199, 241, 5, 55, 244,
+ 230, 23, 116, 236, 196, 191, 8, 25, 239, 192, 231, 80, 171, 10, 21,
+ 171, 196, 57, 198, 9, 148, 158, 238, 151, 55, 44, 25, 203, 215, 185,
+ 85, 223, 194, 207, 158, 79, 118, 129, 17, 39, 149, 201, 210, 242, 208,
+ 246, 9, 241, 131, 75, 39, 57, 206, 234, 142, 119, 98, 202, 148, 116,
+ 148, 135, 202, 241, 227, 216, 222, 124, 183, 168, 210, 22, 121, 36, 245,
+ 240, 89, 209, 243, 35, 156, 216, 67, 122, 254, 72, 207, 71, 135, 204,
+ 47, 196, 7, 53, 84, 242, 147, 7, 120, 240, 233, 67, 111, 59, 196,
+ 99, 167, 130, 126, 44, 208, 101, 172, 244, 249, 42, 229, 71, 233, 41,
+ 63, 135, 115, 63, 255, 95, 61, 127, 156, 227, 200, 199, 158, 110, 242,
+ 180, 95, 213, 59, 127, 121, 166, 126, 248, 213, 35, 117, 178, 49, 219,
+ 65, 158, 23, 133, 195, 218, 247, 143, 117, 228, 179, 242, 69, 97, 126,
+ 203, 221, 99, 22, 57, 40, 125, 197, 80, 194, 47, 85, 108, 118, 224,
+ 115, 172, 232, 176, 175, 11, 12, 148, 63, 167, 165, 252, 40, 127, 123,
+ 62, 158, 145, 233, 109, 51, 182, 72, 243, 177, 151, 75, 234, 252, 121,
+ 107, 196, 193, 150, 77, 122, 59, 242, 41, 189, 110, 158, 186, 142, 223,
+ 113, 203, 186, 146, 243, 131, 15, 130, 87, 52, 29, 49, 76, 154, 15,
+ 93, 175, 114, 235, 180, 87, 212, 66, 62, 179, 139, 52, 31, 42, 199,
+ 149, 247, 151, 169, 183, 109, 218, 40, 201, 231, 89, 224, 79, 229, 255,
+ 76, 148, 246, 59, 212, 79, 200, 241, 89, 20, 20, 82, 97, 177, 19,
+ 62, 148, 158, 250, 29, 57, 62, 79, 131, 119, 222, 75, 73, 114, 228,
+ 67, 245, 165, 231, 195, 108, 117, 243, 71, 155, 212, 31, 55, 123, 160,
+ 94, 90, 101, 172, 164, 254, 92, 170, 88, 213, 216, 195, 201, 121, 84,
+ 161, 225, 155, 213, 29, 234, 122, 242, 252, 150, 189, 234, 106, 253, 127,
+ 87, 83, 125, 150, 146, 231, 96, 189, 97, 165, 10, 143, 151, 30, 103,
+ 202, 135, 242, 149, 226, 19, 242, 131, 127, 139, 1, 113, 210, 242, 80,
+ 57, 166, 86, 188, 161, 254, 102, 173, 175, 36, 159, 98, 47, 202, 191,
+ 184, 148, 34, 205, 135, 210, 167, 84, 248, 90, 189, 108, 118, 61, 73,
+ 62, 251, 94, 76, 48, 221, 117, 194, 135, 250, 97, 58, 95, 179, 207,
+ 156, 85, 15, 169, 95, 64, 58, 254, 201, 57, 114, 107, 247, 68, 105,
+ 62, 116, 158, 40, 63, 41, 62, 115, 210, 190, 206, 60, 95, 219, 201,
+ 254, 93, 140, 47, 40, 63, 57, 121, 58, 254, 240, 124, 217, 59, 225,
+ 210, 124, 40, 253, 131, 15, 207, 169, 55, 123, 254, 44, 25, 143, 109,
+ 184, 112, 113, 101, 201, 72, 71, 62, 163, 38, 246, 83, 251, 165, 175,
+ 13, 167, 124, 228, 226, 58, 239, 61, 151, 183, 245, 104, 39, 205, 135,
+ 202, 33, 215, 175, 197, 187, 110, 110, 50, 105, 28, 249, 208, 113, 165,
+ 227, 76, 215, 135, 20, 159, 202, 7, 185, 251, 163, 227, 165, 249, 80,
+ 122, 185, 117, 186, 124, 95, 229, 202, 117, 157, 216, 121, 186, 30, 40,
+ 189, 156, 60, 65, 23, 123, 134, 244, 26, 46, 205, 135, 174, 51, 57,
+ 121, 12, 23, 70, 104, 150, 56, 57, 15, 167, 246, 129, 234, 15, 141,
+ 55, 165, 248, 156, 34, 19, 31, 38, 166, 72, 243, 161, 227, 44, 23,
+ 175, 22, 244, 39, 215, 207, 57, 177, 99, 116, 157, 211, 254, 209, 241,
+ 145, 242, 167, 215, 125, 111, 55, 42, 224, 36, 110, 73, 158, 83, 146,
+ 247, 60, 250, 167, 197, 126, 81, 255, 37, 37, 207, 250, 197, 217, 71,
+ 251, 213, 147, 230, 67, 237, 134, 156, 61, 28, 246, 151, 209, 71, 61,
+ 69, 122, 124, 44, 114, 201, 200, 51, 56, 199, 103, 224, 218, 46, 210,
+ 124, 232, 60, 81, 126, 82, 124, 174, 63, 217, 152, 115, 246, 61, 233,
+ 253, 14, 93, 87, 114, 246, 103, 209, 189, 207, 175, 15, 119, 194, 103,
+ 121, 102, 17, 254, 244, 132, 38, 150, 184, 240, 137, 255, 53, 245, 198,
+ 181, 93, 36, 237, 170, 70, 245, 91, 185, 105, 19, 165, 249, 208, 243,
+ 190, 30, 63, 87, 230, 91, 248, 197, 75, 242, 233, 19, 244, 193, 31,
+ 151, 147, 164, 159, 55, 209, 184, 85, 46, 94, 213, 212, 249, 99, 194,
+ 130, 34, 222, 46, 248, 152, 233, 169, 92, 82, 124, 146, 15, 196, 250,
+ 23, 94, 237, 228, 60, 92, 164, 163, 253, 251, 113, 74, 13, 190, 212,
+ 39, 210, 254, 107, 76, 147, 57, 69, 50, 156, 244, 107, 82, 183, 32,
+ 254, 135, 49, 196, 18, 63, 203, 241, 249, 218, 235, 250, 133, 220, 9,
+ 210, 242, 80, 122, 202, 79, 138, 207, 35, 245, 55, 10, 221, 104, 34,
+ 25, 207, 91, 248, 201, 240, 201, 254, 113, 235, 203, 211, 19, 157, 237,
+ 47, 204, 231, 116, 84, 31, 229, 206, 235, 188, 106, 221, 158, 181, 249,
+ 47, 79, 73, 127, 97, 245, 55, 102, 190, 146, 231, 108, 133, 239, 207,
+ 46, 88, 95, 41, 185, 31, 164, 118, 85, 46, 110, 25, 244, 195, 186,
+ 33, 225, 45, 137, 36, 31, 43, 253, 60, 144, 199, 91, 146, 207, 111,
+ 223, 110, 26, 88, 188, 141, 82, 50, 110, 177, 198, 43, 51, 128, 79,
+ 35, 73, 62, 247, 182, 213, 237, 210, 151, 151, 142, 127, 172, 244, 174,
+ 229, 185, 184, 99, 98, 151, 153, 173, 156, 237, 187, 205, 244, 84, 30,
+ 185, 245, 222, 243, 86, 244, 232, 33, 33, 68, 146, 143, 149, 254, 16,
+ 220, 15, 146, 228, 243, 211, 189, 238, 201, 53, 131, 156, 228, 129, 88,
+ 232, 233, 58, 47, 3, 215, 68, 73, 62, 235, 107, 235, 135, 159, 15,
+ 113, 197, 135, 210, 187, 150, 231, 23, 191, 207, 199, 84, 11, 112, 242,
+ 28, 214, 178, 79, 238, 202, 19, 253, 44, 89, 121, 170, 247, 188, 218,
+ 175, 126, 5, 87, 124, 40, 189, 107, 59, 182, 58, 156, 211, 189, 104,
+ 225, 100, 156, 245, 83, 1, 127, 152, 69, 30, 43, 95, 231, 124, 38,
+ 189, 31, 89, 100, 92, 69, 105, 62, 148, 158, 158, 35, 72, 241, 81,
+ 77, 62, 93, 244, 101, 89, 105, 62, 148, 94, 238, 28, 96, 140, 86,
+ 251, 169, 103, 41, 105, 62, 148, 190, 152, 49, 133, 255, 176, 167, 116,
+ 60, 223, 161, 247, 210, 175, 7, 213, 113, 228, 67, 233, 169, 253, 138,
+ 237, 253, 46, 191, 194, 197, 185, 86, 213, 187, 59, 83, 31, 133, 74,
+ 243, 161, 244, 114, 242, 68, 189, 106, 53, 179, 78, 13, 71, 62, 148,
+ 158, 202, 67, 237, 190, 228, 121, 230, 181, 202, 11, 87, 134, 73, 243,
+ 161, 244, 207, 63, 104, 198, 103, 166, 253, 45, 233, 223, 151, 101, 37,
+ 44, 14, 115, 50, 239, 148, 142, 242, 145, 139, 15, 219, 121, 15, 158,
+ 254, 155, 11, 62, 148, 158, 158, 111, 74, 230, 21, 212, 169, 183, 114,
+ 67, 43, 23, 126, 80, 244, 95, 114, 241, 207, 142, 163, 202, 191, 234,
+ 141, 145, 230, 67, 233, 229, 250, 197, 31, 62, 248, 251, 139, 81, 142,
+ 124, 168, 28, 212, 191, 203, 237, 79, 163, 79, 126, 235, 59, 125, 140,
+ 52, 31, 74, 47, 215, 175, 109, 198, 46, 197, 218, 59, 217, 167, 80,
+ 122, 42, 143, 156, 125, 158, 114, 178, 74, 133, 214, 99, 164, 249, 80,
+ 122, 185, 253, 242, 224, 27, 147, 159, 255, 250, 190, 252, 121, 157, 125,
+ 62, 163, 179, 60, 97, 227, 27, 200, 63, 196, 60, 225, 168, 229, 210,
+ 121, 194, 246, 121, 131, 82, 124, 48, 79, 184, 209, 218, 252, 231, 121,
+ 98, 158, 112, 199, 109, 210, 121, 131, 246, 121, 172, 174, 242, 132, 159,
+ 28, 145, 207, 239, 149, 227, 131, 121, 194, 123, 214, 73, 243, 161, 249,
+ 175, 114, 249, 144, 152, 39, 188, 254, 134, 116, 126, 166, 125, 30, 173,
+ 171, 60, 225, 29, 253, 164, 243, 123, 237, 243, 52, 93, 229, 9, 143,
+ 12, 249, 159, 207, 19, 182, 207, 127, 166, 227, 230, 44, 79, 56, 152,
+ 228, 63, 207, 28, 243, 132, 123, 105, 229, 207, 177, 237, 243, 241, 157,
+ 230, 9, 199, 73, 231, 9, 219, 231, 205, 75, 233, 51, 230, 9, 127,
+ 241, 6, 242, 249, 49, 79, 216, 217, 121, 184, 125, 126, 175, 220, 124,
+ 97, 158, 240, 169, 47, 164, 249, 216, 247, 203, 85, 158, 240, 170, 141,
+ 242, 249, 189, 114, 242, 96, 158, 240, 242, 126, 210, 124, 168, 60, 114,
+ 235, 11, 243, 132, 191, 237, 146, 255, 124, 45, 204, 19, 238, 177, 60,
+ 255, 249, 90, 152, 39, 124, 232, 88, 254, 243, 172, 48, 79, 184, 210,
+ 172, 252, 231, 125, 97, 158, 112, 201, 245, 249, 207, 179, 194, 60, 225,
+ 153, 107, 242, 159, 247, 133, 121, 194, 186, 133, 249, 207, 215, 194, 60,
+ 97, 223, 207, 243, 159, 175, 133, 121, 194, 35, 230, 230, 63, 95, 11,
+ 243, 132, 191, 158, 150, 255, 124, 45, 204, 19, 46, 31, 39, 127, 110,
+ 35, 151, 223, 139, 121, 194, 67, 231, 120, 75, 230, 9, 219, 231, 27,
+ 211, 243, 10, 103, 121, 194, 51, 150, 75, 231, 175, 210, 117, 33, 151,
+ 191, 138, 121, 194, 207, 207, 201, 231, 247, 202, 229, 121, 98, 158, 240,
+ 227, 69, 242, 249, 189, 114, 249, 198, 152, 39, 220, 252, 158, 124, 222,
+ 178, 125, 158, 175, 179, 60, 225, 139, 38, 233, 188, 83, 251, 124, 99,
+ 87, 121, 194, 219, 226, 228, 243, 177, 229, 248, 200, 229, 9, 187, 155,
+ 79, 219, 218, 239, 214, 162, 181, 225, 249, 207, 167, 197, 60, 225, 240,
+ 140, 252, 231, 247, 98, 158, 240, 222, 21, 249, 207, 55, 198, 60, 225,
+ 57, 67, 243, 159, 255, 140, 121, 194, 63, 116, 201, 255, 247, 83, 48,
+ 79, 248, 206, 128, 252, 127, 63, 5, 243, 132, 47, 68, 230, 255, 123,
+ 37, 152, 39, 236, 63, 60, 255, 223, 115, 193, 60, 225, 228, 33, 249,
+ 255, 94, 9, 230, 9, 251, 13, 205, 255, 247, 92, 48, 79, 56, 116,
+ 88, 254, 191, 159, 130, 121, 194, 127, 15, 207, 255, 247, 83, 48, 79,
+ 248, 240, 136, 252, 127, 63, 5, 243, 132, 87, 140, 200, 255, 247, 83,
+ 48, 79, 56, 96, 182, 171, 60, 97, 154, 63, 228, 58, 255, 16, 243,
+ 132, 231, 244, 245, 118, 35, 143, 145, 230, 247, 154, 243, 134, 157, 229,
+ 9, 159, 157, 226, 42, 79, 216, 54, 207, 216, 85, 158, 240, 190, 246,
+ 210, 121, 194, 238, 230, 139, 98, 158, 240, 166, 175, 228, 243, 123, 229,
+ 242, 199, 48, 79, 56, 97, 190, 52, 31, 154, 183, 33, 151, 111, 140,
+ 121, 194, 103, 141, 68, 54, 159, 86, 238, 121, 1, 230, 9, 87, 89,
+ 43, 159, 111, 44, 247, 188, 0, 243, 132, 31, 157, 83, 186, 200, 55,
+ 54, 231, 209, 202, 229, 247, 98, 158, 240, 142, 155, 133, 100, 243, 141,
+ 229, 242, 159, 49, 79, 56, 118, 135, 124, 126, 175, 220, 56, 99, 158,
+ 176, 223, 110, 105, 62, 180, 95, 114, 250, 131, 121, 194, 251, 77, 69,
+ 92, 172, 11, 251, 124, 124, 233, 60, 225, 217, 239, 87, 114, 35, 223,
+ 216, 245, 186, 192, 60, 225, 239, 38, 86, 146, 205, 203, 149, 155, 47,
+ 204, 19, 94, 56, 71, 58, 191, 215, 221, 188, 38, 204, 19, 62, 244,
+ 169, 124, 190, 177, 92, 94, 46, 230, 9, 107, 102, 75, 207, 23, 165,
+ 151, 211, 31, 204, 19, 174, 59, 93, 58, 47, 215, 221, 124, 90, 204,
+ 19, 254, 104, 190, 124, 190, 177, 92, 30, 8, 230, 9, 199, 175, 144,
+ 207, 55, 150, 91, 239, 152, 39, 252, 217, 52, 249, 124, 45, 185, 113,
+ 198, 60, 225, 47, 22, 72, 63, 55, 183, 207, 219, 114, 149, 39, 124,
+ 106, 181, 116, 126, 175, 125, 254, 142, 171, 60, 97, 238, 176, 124, 190,
+ 177, 220, 57, 54, 230, 9, 159, 217, 35, 159, 223, 75, 243, 133, 93,
+ 229, 9, 159, 253, 92, 154, 143, 253, 247, 75, 92, 229, 9, 191, 59,
+ 159, 184, 145, 223, 235, 122, 189, 99, 158, 112, 102, 123, 111, 23, 124,
+ 168, 127, 119, 157, 111, 140, 121, 194, 83, 155, 74, 231, 9, 219, 231,
+ 249, 186, 202, 19, 94, 122, 94, 58, 79, 152, 218, 83, 57, 62, 152,
+ 39, 156, 244, 151, 124, 94, 46, 125, 158, 70, 247, 187, 206, 242, 132,
+ 175, 45, 145, 206, 19, 182, 127, 30, 39, 181, 95, 198, 60, 225, 220,
+ 185, 210, 242, 208, 231, 148, 114, 207, 25, 49, 79, 248, 143, 123, 210,
+ 121, 194, 246, 207, 229, 92, 229, 9, 47, 158, 45, 253, 220, 193, 62,
+ 63, 87, 234, 253, 36, 167, 130, 46, 21, 216, 246, 161, 244, 249, 170,
+ 125, 158, 177, 212, 121, 38, 230, 9, 215, 25, 47, 157, 39, 76, 243,
+ 152, 104, 30, 145, 84, 190, 49, 230, 9, 59, 123, 127, 2, 205, 199,
+ 165, 121, 64, 22, 126, 18, 249, 207, 152, 39, 252, 60, 45, 255, 249,
+ 189, 152, 39, 28, 213, 53, 255, 249, 198, 152, 39, 124, 234, 75, 249,
+ 188, 92, 185, 252, 94, 204, 19, 94, 188, 76, 62, 223, 152, 174, 91,
+ 87, 121, 194, 157, 210, 165, 249, 208, 188, 58, 57, 255, 142, 121, 194,
+ 37, 63, 146, 246, 59, 148, 143, 156, 63, 93, 24, 20, 82, 97, 196,
+ 71, 210, 121, 194, 148, 143, 156, 223, 193, 60, 97, 253, 60, 233, 60,
+ 97, 251, 124, 61, 154, 103, 231, 44, 79, 120, 211, 34, 249, 188, 92,
+ 154, 175, 231, 42, 79, 248, 241, 28, 233, 113, 182, 207, 59, 118, 149,
+ 39, 188, 118, 137, 124, 126, 175, 92, 158, 30, 230, 9, 215, 214, 19,
+ 217, 124, 27, 185, 231, 185, 152, 39, 92, 90, 47, 157, 223, 235, 110,
+ 126, 29, 230, 9, 183, 155, 37, 159, 111, 76, 231, 203, 85, 158, 112,
+ 253, 31, 229, 243, 123, 229, 226, 13, 204, 19, 222, 112, 72, 154, 143,
+ 187, 121, 185, 152, 39, 252, 231, 62, 34, 155, 175, 37, 199, 7, 243,
+ 132, 55, 237, 146, 207, 55, 150, 203, 91, 198, 60, 97, 206, 32, 159,
+ 223, 43, 55, 206, 152, 39, 252, 241, 199, 210, 124, 220, 205, 239, 197,
+ 60, 225, 139, 75, 165, 243, 123, 221, 205, 55, 198, 60, 225, 175, 22,
+ 203, 231, 27, 211, 245, 230, 42, 79, 120, 248, 114, 249, 188, 83, 57,
+ 253, 193, 60, 225, 249, 122, 249, 124, 99, 185, 113, 198, 60, 225, 6,
+ 243, 164, 243, 132, 237, 191, 247, 64, 251, 235, 44, 79, 248, 249, 92,
+ 23, 121, 194, 162, 223, 146, 179, 27, 152, 39, 252, 197, 121, 249, 124,
+ 99, 57, 187, 129, 121, 194, 135, 166, 74, 143, 15, 149, 71, 46, 15,
+ 4, 243, 132, 7, 164, 203, 231, 27, 203, 237, 11, 48, 79, 56, 104,
+ 134, 252, 247, 34, 229, 214, 41, 230, 9, 47, 153, 33, 157, 223, 235,
+ 152, 175, 39, 157, 39, 60, 101, 150, 52, 31, 154, 31, 44, 151, 151,
+ 139, 121, 194, 181, 230, 17, 217, 252, 94, 107, 252, 42, 157, 39, 60,
+ 230, 161, 82, 246, 253, 54, 114, 253, 194, 60, 225, 199, 131, 228, 243,
+ 114, 173, 121, 213, 210, 121, 194, 81, 243, 228, 243, 163, 228, 226, 103,
+ 204, 19, 86, 206, 118, 33, 143, 155, 249, 198, 152, 39, 156, 150, 74,
+ 100, 191, 247, 39, 55, 95, 152, 39, 220, 120, 150, 116, 158, 176, 187,
+ 223, 23, 198, 60, 225, 238, 74, 233, 60, 97, 251, 188, 99, 87, 121,
+ 194, 207, 206, 121, 203, 230, 247, 202, 217, 85, 204, 19, 62, 156, 37,
+ 157, 39, 76, 243, 113, 229, 242, 141, 49, 79, 248, 254, 30, 111, 217,
+ 252, 94, 185, 124, 45, 204, 19, 94, 111, 116, 149, 39, 76, 243, 131,
+ 93, 231, 27, 99, 158, 240, 123, 251, 189, 101, 243, 123, 229, 228, 193,
+ 60, 225, 85, 223, 72, 231, 9, 211, 124, 92, 185, 124, 54, 204, 19,
+ 190, 114, 198, 157, 252, 94, 215, 235, 20, 243, 132, 235, 127, 227, 138,
+ 15, 205, 15, 118, 157, 223, 139, 121, 194, 191, 124, 235, 78, 126, 47,
+ 205, 23, 150, 206, 19, 62, 127, 211, 21, 31, 247, 242, 159, 49, 79,
+ 216, 243, 168, 124, 126, 175, 156, 60, 152, 39, 252, 225, 13, 249, 252,
+ 94, 185, 115, 0, 204, 19, 246, 184, 45, 159, 223, 43, 151, 111, 140,
+ 121, 194, 47, 238, 74, 243, 161, 249, 184, 114, 249, 198, 152, 39, 252,
+ 233, 69, 249, 252, 94, 57, 187, 138, 121, 194, 69, 142, 72, 243, 161,
+ 242, 200, 229, 27, 99, 158, 240, 143, 87, 228, 243, 123, 229, 228, 193,
+ 60, 225, 152, 195, 210, 124, 236, 243, 124, 93, 229, 9, 31, 185, 33,
+ 159, 223, 43, 199, 7, 243, 132, 43, 184, 224, 99, 255, 254, 3, 87,
+ 121, 194, 239, 236, 151, 207, 239, 149, 243, 95, 152, 39, 124, 97, 190,
+ 52, 31, 119, 191, 111, 133, 121, 194, 158, 159, 200, 231, 247, 202, 249,
+ 119, 204, 19, 158, 60, 95, 154, 143, 253, 247, 210, 92, 229, 9, 239,
+ 250, 88, 62, 191, 87, 78, 30, 204, 19, 222, 55, 95, 154, 143, 187,
+ 223, 7, 193, 60, 97, 63, 39, 207, 29, 162, 90, 19, 225, 157, 247,
+ 198, 34, 177, 94, 65, 204, 239, 179, 37, 52, 166, 126, 0, 113, 146,
+ 70, 196, 197, 251, 7, 4, 4, 18, 155, 63, 78, 68, 79, 253, 251,
+ 177, 130, 72, 252, 233, 129, 111, 174, 151, 153, 87, 78, 193, 88, 47,
+ 125, 225, 88, 175, 236, 66, 86, 222, 246, 127, 133, 197, 223, 35, 68,
+ 198, 186, 159, 35, 249, 182, 169, 179, 96, 215, 168, 111, 92, 173, 214,
+ 49, 77, 235, 122, 119, 249, 243, 243, 167, 104, 88, 252, 42, 196, 147,
+ 40, 152, 95, 149, 195, 119, 38, 123, 138, 237, 138, 50, 146, 28, 143,
+ 88, 47, 44, 63, 142, 229, 208, 126, 35, 177, 157, 246, 245, 251, 26,
+ 215, 60, 173, 204, 39, 152, 106, 240, 243, 110, 156, 125, 165, 152, 172,
+ 48, 117, 128, 178, 117, 80, 54, 220, 84, 195, 128, 101, 175, 166, 41,
+ 76, 103, 43, 198, 26, 159, 7, 119, 228, 245, 141, 202, 91, 240, 176,
+ 236, 5, 148, 77, 106, 84, 222, 130, 215, 237, 204, 24, 227, 233, 123,
+ 215, 212, 254, 223, 22, 183, 148, 105, 161, 236, 36, 148, 53, 254, 182,
+ 184, 133, 246, 196, 193, 95, 255, 31, 123, 95, 1, 87, 213, 182, 173,
+ 191, 232, 110, 65, 58, 164, 148, 6, 233, 70, 148, 84, 80, 164, 67,
+ 233, 238, 6, 165, 149, 80, 26, 165, 20, 65, 5, 233, 110, 16, 73,
+ 105, 164, 59, 5, 105, 9, 165, 164, 255, 123, 123, 166, 247, 112, 125,
+ 231, 220, 115, 239, 123, 239, 190, 247, 126, 255, 115, 182, 191, 15, 215,
+ 94, 107, 206, 49, 190, 49, 230, 152, 177, 214, 158, 115, 46, 201, 171,
+ 122, 66, 117, 125, 223, 109, 57, 245, 129, 32, 196, 83, 215, 71, 121,
+ 117, 50, 176, 115, 67, 103, 206, 57, 195, 206, 73, 195, 206, 13, 132,
+ 123, 215, 253, 56, 247, 1, 150, 247, 10, 236, 92, 239, 153, 115, 112,
+ 219, 220, 225, 239, 200, 130, 249, 149, 3, 216, 22, 9, 59, 254, 225,
+ 149, 155, 103, 142, 241, 207, 28, 247, 160, 255, 122, 28, 121, 230, 248,
+ 230, 153, 227, 127, 245, 243, 183, 247, 129, 97, 252, 193, 251, 8, 255,
+ 224, 58, 254, 31, 92, 135, 115, 255, 135, 239, 99, 252, 131, 235, 55,
+ 255, 193, 117, 6, 248, 251, 167, 96, 49, 203, 242, 183, 119, 99, 34,
+ 126, 127, 239, 37, 124, 239, 115, 248, 155, 164, 16, 192, 49, 42, 132,
+ 1, 161, 67, 104, 16, 45, 116, 250, 221, 238, 17, 16, 227, 108, 127,
+ 203, 183, 9, 27, 223, 62, 130, 181, 89, 241, 176, 255, 3, 197, 167,
+ 198, 138, 197, 60, 23, 213, 126, 183, 13, 11, 131, 197, 199, 225, 125,
+ 244, 31, 239, 168, 253, 117, 206, 242, 223, 242, 253, 34, 231, 87, 185,
+ 191, 47, 7, 37, 224, 63, 202, 249, 241, 222, 197, 255, 120, 12, 228,
+ 192, 142, 206, 2, 130, 190, 193, 226, 11, 9, 241, 111, 114, 16, 64,
+ 155, 33, 5, 179, 31, 230, 132, 20, 20, 115, 52, 186, 51, 117, 236,
+ 108, 28, 220, 144, 178, 181, 115, 178, 55, 49, 130, 12, 156, 77, 28,
+ 45, 12, 172, 207, 180, 25, 103, 142, 124, 37, 126, 197, 223, 181, 26,
+ 191, 115, 30, 250, 157, 116, 127, 255, 57, 253, 155, 255, 127, 121, 247,
+ 215, 175, 121, 127, 149, 251, 115, 124, 211, 162, 252, 126, 155, 244, 159,
+ 173, 7, 55, 129, 92, 50, 96, 45, 194, 217, 183, 95, 34, 194, 234,
+ 216, 143, 55, 145, 254, 174, 221, 190, 18, 191, 141, 95, 108, 249, 81,
+ 14, 112, 223, 211, 157, 241, 109, 202, 25, 91, 110, 72, 57, 26, 24,
+ 26, 90, 56, 67, 223, 75, 227, 215, 54, 28, 241, 255, 104, 57, 232,
+ 35, 253, 123, 202, 1, 46, 247, 223, 85, 14, 170, 176, 62, 52, 3,
+ 200, 162, 254, 187, 24, 255, 245, 163, 122, 77, 213, 196, 253, 55, 206,
+ 255, 90, 14, 190, 176, 250, 156, 34, 249, 123, 186, 126, 125, 215, 247,
+ 127, 228, 9, 183, 231, 87, 63, 35, 254, 75, 254, 145, 191, 1, 139,
+ 81, 132, 95, 234, 54, 41, 224, 254, 247, 237, 5, 60, 141, 147, 185,
+ 129, 177, 157, 27, 135, 179, 153, 193, 79, 253, 255, 247, 15, 39, 167,
+ 179, 137, 187, 179, 139, 163, 137, 19, 231, 153, 132, 240, 80, 251, 126,
+ 82, 247, 183, 115, 255, 207, 126, 244, 215, 143, 255, 105, 199, 32, 252,
+ 221, 49, 194, 223, 149, 211, 12, 244, 203, 88, 226, 28, 56, 38, 1,
+ 233, 217, 36, 255, 94, 198, 77, 58, 165, 239, 233, 224, 231, 225, 199,
+ 191, 202, 253, 149, 134, 36, 236, 31, 45, 58, 124, 114, 237, 191, 25,
+ 8, 255, 69, 64, 255, 199, 129, 240, 191, 140, 255, 43, 54, 35, 254,
+ 15, 227, 127, 195, 23, 255, 200, 94, 164, 223, 0, 242, 127, 19, 126,
+ 75, 246, 63, 242, 199, 255, 132, 221, 191, 101, 39, 202, 25, 160, 254,
+ 55, 227, 172, 236, 223, 242, 203, 191, 195, 15, 255, 200, 110, 228, 223,
+ 176, 21, 13, 0, 29, 0, 227, 55, 128, 249, 7, 248, 173, 60, 63,
+ 228, 253, 144, 255, 179, 79, 144, 255, 13, 126, 248, 61, 219, 145, 207,
+ 216, 140, 246, 147, 157, 112, 254, 88, 48, 96, 3, 224, 156, 1, 238,
+ 191, 136, 179, 121, 127, 200, 195, 250, 201, 71, 232, 103, 252, 113, 214,
+ 15, 255, 85, 31, 252, 108, 251, 217, 50, 63, 107, 247, 89, 123, 127,
+ 216, 136, 7, 159, 24, 11, 3, 1, 12, 132, 0, 68, 0, 231, 254,
+ 73, 252, 72, 255, 35, 63, 1, 144, 137, 119, 198, 55, 103, 253, 113,
+ 214, 15, 63, 199, 194, 127, 198, 7, 63, 219, 126, 182, 204, 127, 148,
+ 55, 22, 224, 241, 195, 94, 66, 192, 157, 24, 6, 18, 24, 206, 195,
+ 64, 10, 159, 20, 7, 159, 136, 15, 64, 241, 79, 226, 71, 122, 50,
+ 32, 227, 60, 144, 73, 12, 116, 16, 158, 241, 7, 14, 224, 242, 35,
+ 30, 126, 43, 22, 254, 21, 251, 255, 200, 118, 76, 224, 123, 60, 80,
+ 46, 68, 128, 27, 41, 224, 76, 9, 3, 53, 252, 97, 48, 252, 65,
+ 55, 124, 17, 38, 12, 23, 224, 15, 243, 1, 24, 254, 0, 63, 210,
+ 93, 0, 121, 105, 129, 44, 106, 32, 155, 28, 232, 34, 1, 186, 9,
+ 0, 23, 236, 51, 177, 240, 95, 241, 193, 207, 245, 253, 172, 237, 63,
+ 202, 28, 255, 140, 221, 100, 128, 23, 13, 224, 12, 183, 129, 9, 134,
+ 139, 48, 176, 192, 192, 10, 3, 27, 124, 114, 54, 0, 199, 31, 224,
+ 71, 58, 54, 144, 151, 5, 200, 98, 2, 178, 47, 0, 93, 148, 64,
+ 247, 15, 63, 224, 159, 137, 133, 179, 62, 248, 185, 61, 248, 87, 203,
+ 254, 172, 237, 184, 192, 223, 231, 64, 25, 252, 176, 27, 94, 94, 204,
+ 128, 43, 156, 59, 23, 124, 114, 6, 12, 188, 240, 69, 94, 240, 5,
+ 126, 48, 8, 194, 32, 4, 159, 204, 244, 7, 16, 2, 105, 5, 64,
+ 94, 94, 32, 139, 11, 200, 102, 1, 186, 232, 207, 248, 129, 20, 112,
+ 34, 0, 28, 207, 250, 224, 95, 137, 129, 223, 179, 29, 19, 248, 150,
+ 0, 212, 65, 184, 223, 169, 64, 89, 48, 129, 114, 226, 4, 92, 225,
+ 220, 69, 224, 147, 61, 225, 63, 160, 195, 112, 5, 134, 171, 240, 197,
+ 119, 48, 200, 192, 32, 11, 32, 247, 19, 126, 156, 151, 1, 105, 175,
+ 130, 188, 146, 64, 150, 8, 144, 205, 11, 116, 177, 2, 221, 23, 0,
+ 23, 50, 192, 141, 0, 112, 197, 252, 7, 62, 248, 103, 202, 30, 5,
+ 180, 169, 24, 160, 110, 225, 3, 31, 147, 129, 186, 8, 247, 255, 37,
+ 16, 179, 188, 160, 220, 224, 60, 165, 129, 29, 138, 48, 40, 193, 112,
+ 19, 6, 21, 24, 84, 225, 63, 120, 194, 39, 31, 254, 1, 212, 64,
+ 90, 21, 144, 87, 9, 200, 146, 5, 178, 197, 129, 46, 94, 160, 251,
+ 18, 224, 66, 13, 184, 157, 3, 92, 177, 1, 119, 180, 159, 234, 193,
+ 239, 197, 192, 63, 138, 123, 60, 80, 199, 72, 129, 175, 127, 216, 206,
+ 5, 226, 84, 12, 112, 147, 135, 65, 25, 240, 215, 132, 47, 56, 128,
+ 225, 46, 252, 135, 13, 248, 143, 0, 240, 133, 75, 48, 152, 192, 96,
+ 250, 59, 48, 1, 105, 140, 64, 158, 187, 64, 134, 38, 144, 169, 12,
+ 116, 72, 3, 157, 2, 128, 195, 15, 31, 80, 1, 142, 68, 128, 51,
+ 214, 191, 16, 3, 191, 85, 246, 103, 227, 158, 4, 212, 181, 11, 103,
+ 108, 135, 199, 163, 4, 40, 27, 37, 80, 118, 58, 128, 59, 220, 30,
+ 75, 24, 108, 96, 176, 135, 47, 106, 131, 79, 4, 129, 47, 38, 131,
+ 193, 245, 119, 224, 2, 210, 56, 130, 60, 54, 64, 134, 41, 144, 169,
+ 3, 116, 40, 1, 157, 18, 128, 195, 15, 31, 92, 0, 28, 73, 126,
+ 170, 7, 191, 21, 3, 127, 20, 251, 63, 151, 61, 25, 104, 111, 152,
+ 64, 220, 9, 0, 253, 240, 186, 123, 11, 6, 45, 192, 209, 28, 6,
+ 91, 96, 135, 7, 12, 94, 240, 9, 219, 48, 248, 195, 240, 0, 134,
+ 135, 48, 4, 194, 16, 244, 19, 2, 193, 181, 7, 32, 173, 47, 200,
+ 235, 1, 100, 217, 2, 217, 6, 64, 215, 45, 160, 91, 2, 112, 225,
+ 0, 220, 104, 0, 215, 159, 99, 224, 31, 213, 129, 179, 246, 255, 136,
+ 253, 179, 245, 254, 71, 217, 211, 131, 118, 135, 23, 196, 159, 44, 224,
+ 161, 13, 226, 214, 26, 112, 189, 15, 108, 128, 219, 21, 10, 67, 4,
+ 12, 209, 240, 137, 82, 240, 201, 136, 48, 196, 194, 16, 247, 19, 98,
+ 193, 181, 39, 32, 109, 4, 200, 27, 4, 100, 221, 7, 178, 173, 129,
+ 46, 109, 160, 91, 22, 112, 225, 5, 220, 232, 207, 196, 192, 217, 118,
+ 224, 71, 29, 248, 61, 251, 127, 174, 251, 24, 32, 126, 8, 65, 157,
+ 162, 1, 253, 14, 39, 104, 127, 164, 65, 28, 106, 1, 62, 240, 242,
+ 113, 7, 229, 22, 12, 248, 195, 237, 73, 132, 225, 5, 12, 47, 225,
+ 27, 73, 192, 144, 6, 159, 104, 1, 144, 14, 240, 227, 123, 26, 72,
+ 243, 18, 228, 73, 4, 50, 34, 128, 76, 95, 160, 195, 22, 232, 212,
+ 2, 28, 164, 1, 39, 78, 192, 145, 6, 112, 38, 4, 54, 96, 252,
+ 65, 27, 240, 123, 117, 31, 23, 180, 167, 228, 160, 110, 177, 0, 63,
+ 139, 131, 118, 72, 13, 196, 163, 53, 224, 229, 15, 202, 12, 94, 134,
+ 207, 97, 120, 5, 95, 108, 7, 67, 14, 124, 18, 60, 252, 135, 89,
+ 24, 138, 97, 40, 129, 255, 248, 252, 19, 74, 192, 181, 66, 144, 54,
+ 7, 228, 125, 5, 100, 61, 1, 178, 253, 129, 46, 107, 160, 91, 13,
+ 112, 17, 7, 220, 88, 0, 87, 114, 192, 29, 247, 159, 104, 3, 126,
+ 203, 254, 31, 117, 159, 24, 196, 19, 3, 24, 127, 8, 2, 127, 43,
+ 131, 246, 200, 28, 196, 165, 47, 224, 7, 143, 227, 100, 80, 174, 121,
+ 192, 174, 74, 24, 222, 194, 39, 154, 194, 80, 7, 95, 152, 2, 208,
+ 8, 240, 227, 123, 29, 72, 243, 22, 228, 41, 1, 50, 210, 129, 204,
+ 88, 160, 195, 23, 232, 52, 7, 28, 148, 1, 39, 65, 192, 145, 1,
+ 112, 38, 62, 211, 6, 252, 43, 246, 163, 255, 84, 247, 169, 65, 219,
+ 194, 5, 198, 33, 178, 160, 63, 50, 0, 177, 120, 31, 196, 231, 19,
+ 192, 51, 19, 190, 88, 28, 216, 0, 183, 167, 9, 134, 86, 24, 218,
+ 97, 232, 132, 161, 11, 134, 15, 240, 133, 143, 0, 31, 192, 185, 78,
+ 144, 166, 21, 228, 169, 5, 50, 138, 128, 204, 100, 160, 35, 24, 232,
+ 180, 5, 28, 84, 1, 39, 17, 192, 145, 9, 112, 62, 219, 6, 160,
+ 255, 147, 246, 163, 158, 177, 159, 0, 220, 123, 209, 128, 49, 56, 15,
+ 136, 51, 69, 208, 39, 155, 130, 114, 240, 7, 117, 244, 57, 40, 43,
+ 56, 223, 106, 80, 182, 109, 192, 190, 62, 248, 66, 124, 248, 228, 49,
+ 24, 70, 224, 139, 12, 126, 194, 8, 184, 54, 8, 210, 126, 0, 121,
+ 27, 129, 172, 34, 32, 251, 57, 208, 229, 15, 116, 155, 2, 46, 138,
+ 128, 27, 15, 224, 74, 3, 184, 19, 156, 177, 31, 245, 15, 236, 255,
+ 189, 182, 143, 246, 76, 221, 151, 4, 109, 142, 46, 232, 155, 61, 64,
+ 27, 253, 20, 212, 213, 60, 80, 102, 112, 222, 29, 48, 244, 194, 23,
+ 224, 193, 48, 6, 195, 36, 12, 211, 240, 133, 206, 240, 205, 202, 126,
+ 194, 71, 112, 109, 18, 164, 29, 2, 121, 59, 128, 172, 74, 32, 251,
+ 21, 208, 21, 4, 116, 91, 2, 46, 74, 128, 219, 143, 54, 128, 246,
+ 31, 180, 129, 103, 237, 71, 248, 3, 251, 201, 192, 125, 40, 43, 184,
+ 31, 185, 2, 198, 165, 119, 193, 248, 196, 11, 212, 201, 68, 208, 94,
+ 149, 128, 184, 109, 3, 252, 71, 128, 77, 112, 251, 62, 193, 39, 51,
+ 194, 176, 4, 195, 242, 79, 88, 2, 215, 62, 129, 180, 147, 32, 111,
+ 47, 144, 85, 11, 100, 103, 0, 93, 161, 64, 183, 13, 224, 114, 19,
+ 112, 227, 7, 92, 233, 0, 247, 127, 100, 63, 194, 31, 216, 79, 116,
+ 166, 237, 103, 3, 227, 140, 171, 96, 108, 110, 0, 198, 104, 190, 32,
+ 30, 95, 128, 54, 187, 18, 212, 221, 15, 160, 12, 225, 118, 204, 193,
+ 176, 8, 159, 144, 5, 195, 103, 24, 214, 97, 216, 248, 9, 235, 224,
+ 218, 10, 72, 59, 7, 242, 14, 1, 89, 77, 64, 118, 14, 208, 21,
+ 1, 116, 219, 3, 46, 42, 128, 155, 0, 224, 250, 163, 15, 32, 250,
+ 79, 218, 143, 123, 198, 126, 250, 51, 109, 255, 53, 208, 222, 24, 129,
+ 113, 170, 63, 24, 175, 188, 4, 253, 214, 91, 208, 126, 245, 129, 56,
+ 254, 8, 236, 89, 5, 54, 126, 129, 225, 43, 124, 49, 215, 79, 248,
+ 10, 174, 173, 131, 180, 139, 32, 239, 24, 144, 213, 10, 100, 231, 3,
+ 93, 209, 64, 183, 35, 224, 162, 10, 184, 253, 232, 3, 232, 207, 216,
+ 143, 251, 159, 180, 255, 28, 120, 30, 245, 195, 126, 33, 112, 127, 170,
+ 6, 198, 31, 206, 96, 188, 250, 4, 140, 91, 10, 65, 156, 182, 131,
+ 118, 108, 18, 196, 243, 10, 176, 11, 110, 227, 54, 124, 226, 52, 12,
+ 187, 48, 236, 1, 236, 130, 115, 219, 32, 205, 58, 200, 243, 9, 200,
+ 24, 4, 50, 107, 129, 142, 215, 64, 231, 3, 192, 193, 24, 112, 146,
+ 1, 28, 127, 216, 79, 113, 102, 12, 240, 175, 216, 143, 249, 147, 253,
+ 12, 96, 124, 45, 12, 250, 25, 117, 112, 175, 230, 2, 198, 236, 79,
+ 193, 216, 173, 24, 244, 225, 157, 160, 45, 159, 6, 117, 250, 51, 40,
+ 219, 109, 96, 235, 55, 248, 98, 181, 159, 240, 13, 92, 219, 6, 105,
+ 63, 131, 188, 211, 64, 86, 39, 144, 93, 12, 116, 61, 5, 186, 93,
+ 0, 23, 117, 192, 77, 24, 112, 101, 248, 201, 126, 204, 255, 102, 251,
+ 77, 193, 61, 91, 32, 24, 151, 188, 1, 237, 83, 3, 232, 203, 71,
+ 64, 252, 46, 157, 41, 251, 157, 51, 182, 31, 192, 55, 68, 3, 56,
+ 56, 227, 131, 157, 51, 49, 176, 4, 100, 140, 0, 153, 13, 64, 199,
+ 27, 160, 51, 16, 112, 48, 253, 31, 180, 95, 238, 39, 251, 131, 192,
+ 253, 203, 27, 48, 142, 109, 0, 237, 213, 40, 232, 215, 150, 65, 251,
+ 182, 5, 202, 247, 172, 237, 71, 0, 103, 125, 176, 11, 210, 110, 128,
+ 188, 179, 64, 214, 7, 32, 187, 20, 232, 138, 3, 186, 207, 218, 47,
+ 247, 191, 104, 127, 58, 224, 214, 8, 198, 116, 191, 101, 255, 30, 176,
+ 241, 172, 237, 103, 125, 176, 15, 210, 252, 150, 253, 221, 64, 118, 41,
+ 208, 245, 151, 253, 255, 183, 236, 255, 179, 196, 255, 159, 189, 253, 251,
+ 51, 244, 127, 127, 246, 241, 207, 95, 227, 223, 191, 238, 127, 254, 44,
+ 247, 191, 127, 246, 231, 31, 127, 61, 255, 250, 235, 249, 231, 95, 207,
+ 191, 255, 250, 253, 227, 207, 254, 251, 215, 159, 253, 247, 207, 63, 243,
+ 239, 223, 127, 246, 249, 15, 127, 205, 127, 249, 107, 254, 211, 159, 125,
+ 254, 219, 95, 243, 31, 255, 154, 255, 250, 215, 252, 231, 191, 230, 191,
+ 255, 181, 254, 225, 175, 245, 47, 127, 173, 127, 250, 107, 253, 219, 95,
+ 235, 31, 255, 90, 255, 250, 215, 250, 231, 255, 207, 215, 191, 255, 109,
+ 135, 8, 21, 181, 107, 234, 242, 183, 229, 149, 149, 216, 53, 101, 228,
+ 175, 95, 227, 248, 117, 111, 134, 153, 95, 247, 102, 56, 187, 15, 203,
+ 47, 123, 51, 252, 178, 191, 199, 101, 14, 75, 123, 179, 223, 216, 195,
+ 192, 81, 88, 247, 174, 189, 139, 161, 181, 133, 147, 185, 137, 35, 187,
+ 189, 163, 137, 181, 157, 129, 177, 137, 163, 46, 216, 177, 65, 247, 183,
+ 115, 255, 207, 126, 184, 16, 190, 253, 151, 246, 102, 248, 113, 110, 115,
+ 243, 215, 189, 25, 224, 199, 63, 246, 102, 24, 188, 241, 247, 50, 82,
+ 114, 127, 217, 155, 97, 228, 198, 47, 199, 63, 100, 156, 142, 156, 206,
+ 64, 248, 10, 50, 242, 50, 16, 2, 34, 2, 36, 7, 251, 7, 157,
+ 174, 17, 190, 185, 105, 110, 231, 108, 231, 100, 110, 103, 79, 123, 153,
+ 131, 11, 18, 188, 34, 127, 3, 105, 237, 151, 205, 148, 224, 41, 190,
+ 211, 0, 255, 195, 175, 33, 227, 124, 191, 6, 223, 238, 196, 253, 123,
+ 218, 173, 239, 223, 209, 127, 104, 255, 158, 6, 243, 7, 113, 248, 55,
+ 102, 124, 176, 245, 213, 15, 67, 16, 191, 231, 219, 249, 126, 44, 7,
+ 113, 154, 154, 194, 174, 88, 195, 254, 162, 130, 92, 191, 156, 121, 153,
+ 144, 248, 183, 51, 191, 108, 221, 165, 13, 251, 251, 227, 12, 223, 247,
+ 191, 236, 191, 158, 249, 46, 243, 219, 47, 155, 123, 65, 240, 200, 251,
+ 141, 15, 210, 210, 247, 125, 91, 254, 219, 175, 125, 183, 249, 199, 134,
+ 39, 72, 223, 191, 253, 82, 226, 164, 191, 87, 206, 223, 211, 160, 3,
+ 47, 127, 247, 20, 162, 228, 47, 0, 215, 206, 253, 205, 203, 132, 223,
+ 191, 99, 127, 79, 250, 9, 20, 165, 253, 47, 64, 184, 9, 65, 49,
+ 240, 243, 173, 48, 77, 8, 191, 89, 190, 235, 16, 174, 148, 177, 157,
+ 161, 9, 100, 12, 127, 191, 29, 194, 233, 56, 244, 0, 194, 70, 71,
+ 71, 199, 64, 199, 198, 192, 192, 38, 192, 194, 196, 34, 32, 198, 195,
+ 198, 198, 35, 38, 37, 34, 34, 38, 34, 34, 37, 192, 254, 254, 1,
+ 255, 253, 246, 7, 1, 7, 11, 11, 7, 23, 7, 31, 23, 23, 255,
+ 28, 46, 46, 238, 57, 248, 31, 220, 115, 191, 100, 33, 248, 103, 4,
+ 156, 214, 65, 4, 232, 48, 3, 236, 145, 16, 46, 64, 136, 4, 8,
+ 72, 4, 8, 167, 147, 48, 99, 209, 78, 155, 16, 36, 96, 44, 81,
+ 16, 190, 127, 128, 175, 144, 96, 230, 32, 163, 160, 162, 161, 99, 96,
+ 98, 33, 252, 124, 17, 1, 66, 68, 250, 113, 17, 31, 66, 64, 70,
+ 64, 66, 68, 70, 68, 65, 67, 69, 71, 65, 194, 190, 12, 187, 72,
+ 128, 132, 76, 71, 200, 141, 34, 117, 203, 128, 232, 130, 131, 31, 15,
+ 234, 185, 168, 151, 133, 87, 232, 25, 136, 85, 234, 13, 47, 243, 58,
+ 250, 247, 74, 163, 49, 70, 223, 222, 252, 248, 197, 200, 137, 143, 228,
+ 85, 81, 0, 211, 213, 24, 85, 227, 107, 13, 175, 157, 249, 207, 247,
+ 169, 205, 154, 124, 45, 126, 208, 216, 239, 50, 183, 37, 195, 252, 36,
+ 245, 97, 201, 211, 166, 129, 79, 219, 105, 165, 239, 7, 231, 119, 212,
+ 77, 93, 3, 99, 223, 148, 53, 15, 45, 236, 10, 200, 106, 152, 185,
+ 5, 197, 165, 151, 183, 12, 47, 238, 17, 64, 136, 136, 48, 182, 200,
+ 223, 57, 161, 161, 162, 240, 125, 167, 64, 199, 77, 136, 12, 99, 224,
+ 112, 129, 8, 133, 199, 47, 234, 28, 156, 65, 189, 74, 239, 230, 101,
+ 6, 195, 143, 142, 254, 209, 210, 183, 137, 141, 156, 120, 191, 48, 162,
+ 194, 9, 160, 49, 241, 53, 244, 193, 72, 188, 62, 111, 124, 77, 141,
+ 223, 217, 100, 246, 111, 20, 126, 159, 1, 243, 175, 20, 78, 199, 32,
+ 108, 164, 239, 58, 9, 32, 9, 168, 100, 237, 101, 106, 28, 6, 30,
+ 249, 234, 132, 237, 30, 47, 222, 167, 204, 119, 67, 26, 183, 177, 74,
+ 142, 134, 49, 14, 152, 180, 123, 118, 215, 220, 202, 147, 87, 236, 110,
+ 149, 32, 42, 62, 214, 70, 62, 124, 131, 91, 219, 190, 123, 232, 90,
+ 57, 181, 203, 166, 84, 58, 80, 230, 39, 63, 132, 86, 46, 207, 248,
+ 70, 172, 234, 176, 252, 158, 202, 237, 26, 181, 48, 78, 179, 117, 63,
+ 17, 55, 251, 229, 205, 201, 245, 177, 201, 252, 177, 144, 219, 150, 70,
+ 146, 180, 94, 180, 139, 21, 136, 66, 132, 226, 49, 53, 47, 198, 249,
+ 15, 125, 118, 204, 46, 133, 12, 234, 177, 27, 69, 84, 166, 223, 232,
+ 74, 66, 248, 216, 145, 186, 156, 128, 93, 154, 231, 58, 59, 139, 246,
+ 192, 31, 125, 12, 109, 135, 255, 152, 230, 88, 99, 57, 77, 96, 233,
+ 101, 106, 153, 73, 103, 142, 237, 148, 60, 141, 226, 50, 234, 97, 205,
+ 187, 161, 92, 81, 87, 212, 230, 17, 174, 30, 99, 251, 251, 135, 238,
+ 180, 70, 1, 219, 111, 164, 168, 251, 204, 154, 14, 239, 190, 246, 137,
+ 57, 169, 237, 90, 26, 188, 101, 124, 30, 215, 135, 147, 195, 80, 225,
+ 54, 43, 142, 62, 101, 27, 151, 81, 83, 67, 20, 59, 244, 98, 70,
+ 142, 168, 59, 250, 201, 61, 185, 125, 220, 155, 83, 195, 49, 107, 9,
+ 168, 202, 54, 216, 202, 125, 199, 27, 43, 169, 105, 143, 183, 119, 227,
+ 113, 241, 233, 55, 110, 10, 84, 248, 127, 92, 64, 118, 35, 72, 223,
+ 245, 106, 119, 30, 66, 15, 138, 120, 73, 173, 187, 181, 118, 185, 252,
+ 225, 121, 245, 186, 161, 53, 238, 151, 104, 241, 18, 251, 52, 31, 228,
+ 21, 4, 86, 153, 140, 154, 245, 79, 33, 230, 39, 167, 144, 37, 142,
+ 133, 133, 112, 56, 70, 112, 12, 243, 180, 196, 53, 244, 161, 6, 42,
+ 19, 253, 117, 15, 14, 119, 102, 127, 153, 110, 187, 253, 96, 229, 34,
+ 4, 134, 53, 130, 42, 249, 254, 218, 16, 121, 121, 235, 182, 204, 46,
+ 60, 100, 235, 40, 238, 47, 227, 184, 189, 102, 38, 165, 41, 144, 59,
+ 178, 136, 125, 184, 143, 187, 143, 217, 177, 183, 63, 251, 13, 196, 87,
+ 7, 143, 117, 153, 52, 133, 98, 50, 167, 211, 123, 167, 143, 34, 142,
+ 252, 3, 165, 35, 10, 99, 82, 144, 43, 132, 141, 151, 215, 198, 203,
+ 247, 188, 99, 183, 85, 97, 189, 101, 79, 177, 215, 67, 255, 197, 98,
+ 123, 232, 60, 73, 149, 228, 209, 204, 41, 228, 32, 82, 219, 103, 183,
+ 163, 179, 226, 211, 204, 66, 69, 65, 92, 246, 201, 216, 69, 183, 44,
+ 72, 128, 146, 170, 186, 102, 236, 75, 245, 158, 106, 213, 235, 145, 177,
+ 61, 30, 82, 175, 222, 116, 180, 164, 220, 221, 53, 23, 159, 1, 169,
+ 21, 134, 57, 103, 107, 165, 216, 254, 194, 81, 250, 129, 50, 4, 252,
+ 233, 180, 109, 159, 165, 212, 44, 19, 42, 129, 124, 149, 67, 7, 86,
+ 98, 157, 91, 123, 114, 1, 18, 53, 107, 234, 158, 84, 110, 132, 82,
+ 162, 130, 136, 188, 65, 164, 7, 194, 201, 105, 213, 199, 62, 125, 170,
+ 75, 236, 182, 244, 137, 155, 200, 98, 69, 104, 59, 46, 78, 186, 85,
+ 226, 81, 146, 54, 187, 149, 185, 236, 6, 238, 180, 34, 122, 232, 243,
+ 121, 167, 144, 236, 41, 244, 154, 16, 181, 79, 138, 92, 120, 36, 62,
+ 86, 67, 211, 105, 98, 49, 238, 186, 45, 20, 238, 21, 122, 192, 126,
+ 192, 190, 123, 111, 48, 101, 45, 12, 74, 26, 195, 224, 64, 58, 73,
+ 158, 10, 238, 227, 191, 238, 209, 73, 19, 71, 163, 56, 150, 61, 241,
+ 181, 87, 226, 249, 44, 122, 4, 193, 41, 164, 58, 237, 58, 16, 25,
+ 119, 15, 171, 204, 222, 3, 169, 117, 89, 34, 105, 191, 213, 206, 9,
+ 169, 172, 130, 170, 137, 232, 56, 118, 217, 76, 162, 186, 250, 208, 210,
+ 89, 117, 152, 123, 44, 26, 215, 175, 166, 78, 196, 167, 18, 235, 82,
+ 253, 203, 151, 235, 177, 168, 9, 145, 130, 71, 117, 87, 20, 20, 86,
+ 73, 251, 60, 208, 182, 94, 55, 42, 31, 36, 181, 42, 241, 227, 223,
+ 93, 243, 224, 234, 251, 152, 238, 254, 201, 238, 120, 254, 250, 132, 158,
+ 211, 39, 255, 41, 52, 218, 138, 15, 171, 252, 197, 203, 247, 180, 55,
+ 62, 251, 140, 63, 186, 176, 27, 64, 94, 133, 193, 70, 27, 57, 140,
+ 136, 219, 181, 238, 84, 43, 226, 58, 189, 115, 76, 126, 219, 176, 175,
+ 69, 163, 220, 181, 79, 151, 177, 25, 239, 235, 30, 94, 151, 35, 1,
+ 237, 24, 169, 88, 81, 157, 246, 71, 232, 186, 207, 179, 109, 177, 83,
+ 168, 227, 152, 249, 136, 5, 165, 146, 130, 5, 71, 36, 109, 221, 137,
+ 124, 193, 95, 239, 109, 28, 137, 180, 87, 178, 178, 235, 241, 114, 238,
+ 189, 220, 114, 39, 170, 150, 18, 91, 124, 233, 230, 112, 11, 135, 221,
+ 147, 167, 131, 39, 86, 62, 157, 242, 215, 117, 247, 30, 151, 157, 135,
+ 12, 113, 238, 201, 108, 184, 245, 21, 126, 144, 80, 62, 72, 126, 125,
+ 10, 101, 43, 205, 46, 150, 214, 81, 173, 249, 106, 95, 149, 233, 167,
+ 121, 237, 179, 83, 59, 124, 130, 79, 172, 185, 56, 209, 60, 178, 136,
+ 184, 200, 95, 251, 74, 91, 172, 65, 177, 86, 188, 251, 246, 128, 119,
+ 75, 33, 113, 25, 218, 144, 149, 147, 107, 77, 24, 215, 210, 199, 186,
+ 67, 189, 242, 173, 119, 113, 199, 188, 240, 224, 232, 21, 217, 76, 72,
+ 72, 86, 227, 180, 160, 75, 181, 139, 105, 181, 152, 62, 78, 78, 45,
+ 60, 104, 190, 213, 185, 58, 204, 69, 80, 84, 52, 214, 92, 147, 40,
+ 64, 60, 48, 43, 96, 81, 182, 139, 35, 237, 149, 40, 133, 202, 119,
+ 210, 55, 83, 200, 227, 211, 30, 55, 106, 148, 218, 225, 71, 159, 32,
+ 62, 48, 154, 116, 126, 142, 58, 101, 221, 80, 210, 122, 168, 79, 250,
+ 46, 68, 67, 131, 184, 49, 165, 199, 143, 218, 35, 25, 144, 137, 139,
+ 20, 142, 86, 69, 35, 33, 181, 126, 224, 179, 186, 242, 245, 88, 168,
+ 171, 112, 35, 51, 53, 230, 117, 34, 179, 116, 235, 226, 178, 237, 158,
+ 144, 139, 222, 69, 10, 243, 204, 197, 201, 210, 112, 139, 113, 242, 250,
+ 233, 42, 113, 239, 141, 21, 159, 248, 215, 69, 233, 213, 197, 186, 113,
+ 54, 236, 123, 114, 144, 185, 49, 65, 149, 143, 219, 210, 155, 194, 92,
+ 225, 36, 109, 190, 11, 188, 180, 73, 249, 195, 7, 185, 42, 153, 47,
+ 67, 113, 160, 32, 126, 125, 171, 99, 195, 41, 159, 232, 87, 125, 179,
+ 13, 75, 227, 111, 151, 152, 76, 197, 67, 104, 100, 167, 183, 137, 98,
+ 47, 91, 213, 217, 54, 190, 196, 151, 15, 119, 121, 49, 221, 46, 213,
+ 89, 100, 205, 64, 133, 206, 190, 187, 114, 61, 98, 37, 249, 85, 202,
+ 42, 100, 84, 86, 33, 133, 28, 196, 75, 99, 97, 30, 103, 251, 0,
+ 177, 97, 175, 162, 141, 182, 59, 163, 121, 215, 185, 35, 185, 241, 121,
+ 215, 212, 238, 41, 52, 172, 162, 98, 89, 67, 225, 182, 238, 206, 16,
+ 162, 239, 75, 155, 108, 165, 87, 129, 51, 88, 211, 170, 97, 216, 51,
+ 187, 138, 206, 39, 98, 142, 236, 79, 110, 144, 178, 102, 103, 122, 232,
+ 118, 140, 247, 45, 91, 162, 62, 107, 119, 125, 202, 184, 49, 60, 21,
+ 7, 15, 165, 218, 90, 124, 195, 233, 197, 70, 175, 79, 126, 38, 207,
+ 225, 234, 212, 161, 64, 205, 251, 158, 143, 235, 241, 20, 58, 20, 74,
+ 11, 199, 204, 62, 249, 223, 24, 82, 73, 52, 76, 226, 231, 243, 236,
+ 93, 103, 123, 113, 201, 5, 21, 75, 246, 248, 198, 189, 62, 164, 155,
+ 238, 122, 71, 108, 39, 111, 90, 90, 187, 168, 108, 14, 109, 16, 199,
+ 32, 244, 232, 173, 125, 217, 77, 250, 112, 112, 103, 241, 20, 90, 25,
+ 152, 29, 46, 124, 229, 98, 85, 123, 245, 27, 67, 19, 205, 61, 202,
+ 13, 215, 233, 111, 234, 94, 152, 181, 155, 4, 101, 229, 158, 126, 129,
+ 164, 51, 179, 140, 69, 8, 104, 203, 181, 86, 62, 30, 176, 16, 59,
+ 133, 122, 45, 46, 153, 173, 187, 164, 174, 30, 208, 178, 187, 163, 109,
+ 37, 111, 24, 115, 55, 142, 86, 159, 228, 111, 13, 232, 242, 96, 117,
+ 176, 237, 161, 34, 101, 235, 228, 205, 50, 126, 168, 57, 12, 28, 90,
+ 247, 73, 63, 86, 86, 24, 216, 16, 241, 162, 88, 137, 30, 191, 138,
+ 129, 22, 98, 99, 227, 242, 44, 185, 122, 191, 236, 224, 222, 216, 198,
+ 196, 118, 191, 141, 121, 94, 121, 28, 213, 26, 77, 26, 253, 68, 11,
+ 62, 37, 219, 30, 47, 119, 233, 161, 222, 209, 198, 1, 191, 119, 204,
+ 49, 139, 130, 207, 105, 223, 84, 221, 155, 238, 162, 105, 28, 219, 77,
+ 74, 163, 200, 141, 15, 115, 251, 119, 97, 45, 204, 170, 85, 231, 193,
+ 99, 37, 60, 221, 119, 175, 183, 239, 184, 241, 126, 161, 93, 169, 81,
+ 76, 21, 47, 24, 86, 149, 134, 5, 189, 46, 213, 20, 243, 41, 196,
+ 173, 203, 60, 252, 33, 202, 198, 67, 194, 214, 220, 181, 13, 123, 226,
+ 158, 197, 231, 136, 207, 180, 215, 242, 66, 94, 91, 188, 203, 228, 27,
+ 77, 216, 64, 246, 14, 229, 238, 23, 43, 61, 80, 44, 93, 42, 137,
+ 253, 216, 41, 91, 133, 228, 71, 77, 131, 242, 225, 88, 166, 249, 213,
+ 243, 243, 107, 140, 249, 165, 201, 215, 35, 186, 184, 69, 124, 86, 72,
+ 78, 216, 79, 18, 138, 242, 149, 237, 82, 181, 77, 189, 159, 224, 84,
+ 29, 211, 76, 157, 180, 28, 107, 35, 16, 242, 235, 73, 59, 145, 15,
+ 21, 44, 25, 249, 17, 161, 45, 123, 91, 18, 39, 92, 119, 114, 33,
+ 156, 114, 67, 186, 96, 54, 121, 10, 41, 30, 251, 120, 63, 94, 247,
+ 86, 12, 54, 46, 109, 112, 173, 168, 163, 77, 216, 93, 90, 155, 150,
+ 34, 171, 24, 18, 126, 133, 187, 96, 238, 108, 59, 20, 239, 182, 126,
+ 204, 185, 115, 10, 213, 61, 58, 239, 122, 103, 104, 221, 126, 2, 194,
+ 231, 157, 164, 244, 118, 219, 113, 165, 195, 178, 46, 234, 182, 170, 183,
+ 182, 25, 19, 53, 232, 234, 61, 212, 92, 56, 176, 53, 59, 162, 134,
+ 57, 253, 20, 26, 10, 138, 210, 209, 36, 239, 69, 105, 198, 186, 203,
+ 67, 201, 164, 187, 86, 93, 46, 112, 80, 155, 124, 32, 113, 67, 196,
+ 104, 144, 3, 23, 135, 155, 205, 159, 191, 202, 108, 252, 228, 252, 150,
+ 207, 179, 209, 195, 228, 221, 175, 42, 236, 229, 218, 253, 37, 159, 7,
+ 172, 45, 6, 168, 100, 114, 92, 135, 42, 223, 250, 8, 28, 72, 28,
+ 211, 209, 57, 61, 95, 40, 26, 18, 241, 56, 144, 122, 173, 1, 9,
+ 120, 113, 190, 90, 93, 118, 235, 59, 62, 168, 149, 221, 95, 185, 94,
+ 84, 30, 214, 229, 63, 195, 116, 213, 38, 160, 48, 125, 124, 91, 123,
+ 237, 101, 172, 214, 126, 8, 215, 160, 113, 220, 219, 176, 7, 197, 110,
+ 134, 67, 17, 139, 15, 146, 222, 37, 167, 159, 66, 183, 78, 33, 242,
+ 232, 216, 199, 218, 125, 55, 244, 35, 186, 227, 120, 45, 56, 112, 220,
+ 106, 15, 166, 186, 55, 147, 95, 159, 232, 16, 33, 178, 32, 12, 137,
+ 13, 225, 165, 213, 204, 242, 29, 136, 220, 45, 204, 27, 95, 94, 223,
+ 61, 156, 254, 108, 118, 92, 53, 91, 21, 63, 44, 98, 206, 30, 156,
+ 175, 55, 102, 121, 220, 121, 180, 104, 99, 127, 10, 213, 231, 202, 239,
+ 150, 190, 233, 26, 119, 195, 31, 162, 16, 144, 114, 246, 121, 48, 89,
+ 189, 92, 108, 183, 116, 124, 146, 165, 96, 100, 229, 106, 173, 239, 221,
+ 120, 187, 156, 183, 147, 171, 90, 198, 70, 226, 53, 251, 218, 254, 41,
+ 180, 51, 208, 197, 65, 162, 165, 123, 222, 119, 161, 166, 183, 90, 210,
+ 135, 87, 194, 174, 247, 68, 57, 243, 132, 232, 100, 156, 145, 221, 105,
+ 252, 182, 110, 95, 189, 89, 5, 137, 124, 156, 69, 57, 172, 83, 252,
+ 124, 10, 181, 106, 104, 177, 31, 83, 133, 79, 172, 145, 143, 26, 233,
+ 164, 146, 6, 201, 82, 212, 200, 141, 151, 31, 91, 195, 194, 171, 127,
+ 100, 201, 205, 182, 170, 89, 180, 74, 115, 115, 223, 126, 156, 252, 158,
+ 68, 209, 198, 246, 179, 154, 21, 31, 45, 110, 150, 174, 204, 157, 210,
+ 24, 147, 176, 49, 82, 231, 61, 188, 151, 184, 110, 229, 91, 79, 243,
+ 18, 252, 110, 176, 151, 211, 150, 230, 246, 148, 15, 92, 166, 149, 119,
+ 74, 52, 21, 15, 159, 215, 16, 201, 222, 30, 214, 94, 201, 114, 191,
+ 87, 111, 142, 199, 197, 16, 124, 180, 113, 228, 47, 239, 80, 69, 214,
+ 217, 96, 149, 229, 98, 99, 101, 137, 140, 49, 64, 253, 177, 118, 159,
+ 170, 67, 246, 220, 99, 30, 118, 225, 195, 15, 11, 232, 95, 15, 112,
+ 143, 167, 15, 166, 143, 200, 107, 237, 228, 77, 182, 53, 108, 40, 52,
+ 59, 172, 46, 212, 185, 160, 154, 140, 157, 66, 3, 62, 183, 110, 165,
+ 187, 144, 81, 232, 210, 27, 196, 227, 155, 45, 219, 156, 104, 148, 47,
+ 165, 166, 219, 145, 132, 56, 56, 165, 70, 234, 98, 156, 66, 153, 159,
+ 169, 182, 245, 214, 213, 239, 76, 166, 148, 33, 32, 135, 223, 219, 61,
+ 154, 126, 189, 221, 215, 124, 143, 66, 53, 12, 57, 201, 103, 99, 140,
+ 101, 148, 51, 218, 53, 73, 116, 59, 210, 104, 98, 216, 199, 130, 129,
+ 151, 135, 157, 196, 206, 2, 95, 191, 244, 1, 141, 197, 16, 127, 181,
+ 244, 209, 226, 193, 33, 97, 122, 191, 129, 123, 16, 95, 105, 96, 97,
+ 98, 163, 175, 57, 146, 146, 120, 236, 41, 116, 96, 142, 199, 48, 116,
+ 200, 22, 7, 41, 173, 165, 198, 135, 141, 151, 196, 9, 189, 123, 238,
+ 99, 64, 144, 75, 215, 197, 23, 72, 174, 147, 55, 211, 99, 76, 85,
+ 77, 222, 61, 105, 59, 116, 10, 5, 192, 186, 212, 187, 199, 54, 140,
+ 97, 36, 182, 105, 105, 213, 87, 239, 213, 164, 188, 64, 82, 108, 116,
+ 222, 114, 157, 156, 150, 62, 133, 68, 187, 201, 186, 207, 227, 57, 80,
+ 40, 29, 60, 31, 138, 90, 195, 73, 58, 89, 40, 222, 190, 171, 120,
+ 112, 18, 7, 11, 25, 34, 189, 216, 106, 74, 146, 183, 158, 79, 149,
+ 242, 130, 108, 81, 222, 45, 248, 208, 193, 170, 250, 100, 232, 41, 84,
+ 54, 40, 149, 112, 35, 97, 33, 210, 181, 50, 232, 70, 42, 62, 147,
+ 128, 167, 247, 198, 188, 196, 190, 207, 166, 207, 50, 97, 146, 130, 21,
+ 103, 230, 76, 144, 198, 114, 20, 158, 175, 238, 48, 162, 143, 252, 6,
+ 238, 100, 77, 190, 145, 171, 247, 41, 180, 229, 170, 25, 227, 166, 101,
+ 128, 29, 116, 40, 233, 164, 148, 234, 199, 236, 140, 122, 76, 99, 163,
+ 60, 173, 147, 99, 118, 32, 177, 104, 181, 163, 229, 91, 118, 195, 108,
+ 192, 230, 129, 63, 185, 36, 82, 33, 77, 170, 196, 243, 197, 147, 160,
+ 163, 11, 133, 106, 34, 119, 87, 130, 20, 223, 8, 188, 208, 92, 62,
+ 128, 245, 152, 50, 45, 158, 161, 242, 242, 150, 57, 93, 6, 185, 113,
+ 92, 138, 206, 17, 246, 8, 85, 27, 28, 147, 213, 163, 39, 181, 31,
+ 164, 47, 190, 183, 181, 231, 50, 116, 255, 244, 237, 20, 202, 63, 65,
+ 219, 238, 253, 208, 34, 250, 168, 213, 234, 206, 50, 210, 77, 201, 192,
+ 56, 174, 117, 187, 245, 195, 155, 28, 78, 202, 101, 116, 101, 74, 207,
+ 195, 196, 195, 55, 14, 23, 79, 178, 229, 241, 78, 7, 134, 15, 54,
+ 146, 188, 169, 81, 42, 70, 166, 229, 159, 158, 47, 227, 141, 183, 74,
+ 110, 249, 234, 154, 207, 146, 158, 113, 160, 39, 139, 185, 254, 124, 245,
+ 171, 157, 147, 206, 110, 226, 87, 136, 110, 175, 162, 178, 108, 88, 154,
+ 149, 243, 24, 181, 133, 187, 212, 246, 152, 99, 103, 53, 89, 43, 115,
+ 231, 242, 177, 202, 113, 138, 80, 46, 178, 171, 223, 164, 193, 246, 187,
+ 176, 62, 171, 110, 129, 185, 94, 61, 38, 170, 119, 187, 33, 246, 71,
+ 195, 85, 33, 19, 99, 94, 225, 71, 77, 209, 151, 134, 151, 188, 164,
+ 230, 206, 127, 222, 21, 236, 64, 70, 250, 16, 224, 214, 119, 146, 149,
+ 153, 248, 245, 115, 121, 252, 94, 16, 190, 182, 179, 149, 223, 152, 0,
+ 222, 74, 37, 121, 206, 219, 235, 194, 228, 99, 202, 149, 169, 165, 169,
+ 123, 139, 135, 56, 147, 88, 226, 157, 126, 198, 99, 138, 51, 113, 82,
+ 228, 82, 200, 101, 184, 126, 167, 80, 219, 41, 84, 78, 120, 187, 58,
+ 34, 185, 44, 29, 33, 19, 165, 190, 186, 28, 137, 38, 41, 199, 231,
+ 69, 80, 84, 116, 139, 252, 118, 27, 114, 96, 84, 193, 186, 8, 172,
+ 200, 229, 203, 247, 124, 118, 46, 180, 189, 218, 100, 141, 119, 162, 28,
+ 138, 97, 63, 184, 34, 233, 68, 51, 238, 86, 123, 10, 169, 179, 230,
+ 216, 39, 117, 35, 221, 46, 107, 24, 141, 202, 91, 40, 204, 67, 218,
+ 47, 47, 62, 98, 222, 21, 83, 222, 182, 80, 196, 31, 122, 172, 169,
+ 73, 121, 151, 211, 201, 77, 232, 147, 47, 239, 88, 99, 233, 244, 200,
+ 41, 244, 64, 166, 133, 118, 244, 166, 7, 95, 101, 24, 110, 65, 36,
+ 210, 227, 80, 193, 160, 242, 173, 68, 88, 8, 70, 40, 247, 221, 114,
+ 200, 236, 30, 115, 113, 74, 148, 118, 147, 90, 16, 179, 235, 60, 133,
+ 66, 143, 166, 183, 93, 152, 45, 240, 42, 103, 135, 130, 212, 59, 16,
+ 76, 2, 38, 228, 35, 94, 157, 66, 202, 99, 29, 20, 135, 225, 167,
+ 208, 96, 230, 13, 221, 225, 245, 55, 245, 154, 40, 41, 124, 41, 132,
+ 51, 107, 74, 161, 139, 91, 122, 135, 135, 167, 208, 11, 221, 225, 27,
+ 217, 151, 38, 21, 157, 169, 124, 35, 240, 61, 204, 135, 151, 125, 250,
+ 245, 140, 148, 199, 196, 174, 44, 245, 145, 233, 39, 77, 45, 4, 118,
+ 212, 152, 14, 173, 77, 117, 175, 158, 66, 45, 172, 238, 73, 28, 111,
+ 222, 146, 148, 190, 156, 79, 169, 240, 163, 253, 118, 111, 206, 117, 152,
+ 225, 141, 251, 182, 181, 49, 63, 21, 237, 121, 196, 105, 135, 128, 236,
+ 242, 136, 201, 177, 60, 46, 82, 215, 17, 216, 64, 145, 204, 58, 154,
+ 114, 33, 226, 245, 209, 27, 137, 99, 47, 1, 43, 105, 99, 73, 156,
+ 128, 10, 115, 101, 143, 147, 14, 2, 214, 220, 29, 222, 203, 241, 241,
+ 76, 114, 230, 199, 61, 74, 139, 214, 150, 10, 58, 253, 56, 176, 254,
+ 127, 29, 143, 106, 206, 224, 104, 216, 139, 198, 242, 165, 187, 137, 126,
+ 69, 100, 195, 50, 135, 121, 255, 132, 215, 59, 9, 69, 187, 175, 181,
+ 219, 175, 106, 237, 119, 3, 163, 234, 2, 223, 174, 248, 184, 139, 236,
+ 213, 230, 20, 175, 91, 68, 227, 85, 233, 191, 152, 149, 99, 95, 247,
+ 201, 173, 97, 148, 56, 29, 172, 222, 137, 203, 176, 245, 242, 165, 162,
+ 68, 10, 122, 239, 228, 226, 18, 102, 105, 93, 37, 73, 183, 78, 217,
+ 241, 46, 58, 108, 52, 110, 17, 93, 159, 195, 30, 95, 213, 193, 83,
+ 253, 38, 83, 67, 253, 214, 165, 75, 213, 234, 138, 101, 43, 75, 225,
+ 178, 161, 135, 94, 181, 85, 201, 107, 36, 18, 99, 245, 25, 99, 253,
+ 8, 175, 175, 232, 44, 239, 29, 237, 62, 249, 80, 95, 50, 44, 34,
+ 231, 198, 37, 200, 178, 168, 216, 236, 68, 87, 22, 92, 184, 78, 33,
+ 32, 24, 216, 186, 39, 226, 218, 95, 189, 148, 154, 250, 68, 195, 74,
+ 43, 219, 117, 181, 216, 233, 27, 90, 236, 144, 150, 132, 172, 83, 57,
+ 43, 233, 120, 2, 182, 7, 14, 34, 18, 100, 77, 226, 47, 53, 182,
+ 49, 53, 53, 89, 187, 51, 111, 144, 143, 191, 23, 80, 110, 29, 23,
+ 86, 87, 38, 91, 46, 139, 230, 69, 65, 182, 125, 10, 61, 155, 218,
+ 209, 224, 222, 61, 80, 114, 51, 234, 64, 135, 117, 211, 1, 159, 187,
+ 194, 229, 217, 198, 99, 251, 245, 41, 18, 53, 119, 35, 135, 9, 112,
+ 251, 176, 220, 74, 211, 199, 54, 236, 96, 189, 207, 18, 59, 230, 235,
+ 11, 163, 30, 180, 99, 107, 121, 140, 41, 176, 234, 179, 235, 163, 230,
+ 64, 99, 85, 56, 202, 195, 80, 118, 221, 109, 177, 222, 85, 12, 191,
+ 102, 45, 201, 172, 100, 137, 137, 31, 214, 40, 166, 6, 30, 147, 126,
+ 124, 32, 88, 33, 105, 225, 70, 128, 76, 210, 245, 116, 185, 250, 20,
+ 82, 59, 72, 190, 97, 222, 47, 137, 204, 215, 40, 9, 37, 4, 251,
+ 138, 74, 136, 44, 49, 109, 55, 249, 127, 132, 120, 121, 37, 135, 95,
+ 152, 45, 173, 203, 154, 35, 138, 4, 147, 71, 208, 81, 69, 43, 34,
+ 232, 120, 199, 89, 48, 44, 11, 215, 31, 125, 146, 42, 55, 35, 15,
+ 191, 119, 52, 127, 49, 170, 202, 37, 88, 98, 250, 85, 168, 98, 96,
+ 63, 82, 145, 156, 229, 148, 246, 34, 153, 197, 248, 26, 237, 46, 46,
+ 218, 100, 75, 245, 193, 99, 241, 61, 245, 185, 242, 165, 53, 124, 179,
+ 238, 73, 118, 183, 131, 83, 104, 169, 52, 205, 157, 178, 62, 82, 42,
+ 82, 144, 167, 48, 191, 242, 96, 195, 34, 236, 13, 31, 37, 6, 99,
+ 110, 196, 212, 131, 104, 216, 64, 119, 244, 251, 243, 142, 95, 158, 234,
+ 160, 125, 127, 250, 4, 187, 217, 255, 63, 252, 28, 227, 251, 246, 180,
+ 127, 255, 28, 3, 255, 180, 9, 138, 128, 32, 68, 164, 95, 159, 83,
+ 192, 159, 99, 32, 35, 32, 162, 64, 168, 104, 103, 31, 95, 128, 135,
+ 24, 136, 72, 248, 191, 60, 56, 64, 65, 64, 65, 65, 67, 66, 68,
+ 194, 128, 157, 35, 64, 34, 132, 232, 184, 47, 240, 32, 75, 93, 81,
+ 49, 36, 186, 101, 224, 72, 127, 25, 197, 193, 95, 250, 54, 170, 95,
+ 116, 81, 159, 145, 211, 185, 194, 87, 13, 81, 179, 155, 188, 170, 47,
+ 235, 191, 4, 196, 188, 46, 110, 100, 32, 128, 137, 69, 132, 41, 61,
+ 35, 152, 0, 145, 142, 91, 138, 16, 201, 239, 239, 159, 11, 152, 159,
+ 56, 116, 178, 68, 55, 69, 22, 150, 233, 138, 239, 120, 62, 142, 234,
+ 77, 136, 191, 200, 50, 83, 25, 145, 242, 233, 176, 35, 251, 92, 254,
+ 147, 204, 38, 72, 237, 105, 224, 166, 160, 147, 85, 158, 9, 138, 62,
+ 126, 186, 127, 82, 243, 225, 72, 238, 130, 30, 74, 22, 95, 114, 28,
+ 234, 52, 33, 238, 5, 213, 192, 237, 252, 167, 165, 174, 250, 121, 86,
+ 5, 15, 173, 245, 155, 219, 103, 194, 118, 79, 76, 131, 228, 133, 140,
+ 125, 145, 155, 30, 61, 176, 191, 92, 184, 47, 70, 94, 238, 230, 138,
+ 77, 94, 39, 199, 202, 129, 48, 77, 235, 115, 121, 125, 137, 189, 198,
+ 245, 37, 137, 36, 68, 158, 240, 161, 199, 51, 203, 116, 208, 169, 16,
+ 113, 56, 46, 132, 15, 141, 81, 110, 75, 255, 75, 156, 202, 182, 57,
+ 241, 200, 188, 126, 6, 143, 14, 23, 131, 41, 94, 2, 55, 57, 107,
+ 102, 201, 16, 198, 39, 19, 204, 207, 12, 157, 206, 95, 247, 245, 156,
+ 81, 88, 50, 199, 231, 93, 30, 12, 155, 232, 47, 48, 204, 116, 188,
+ 83, 247, 168, 42, 17, 159, 242, 173, 155, 140, 229, 167, 107, 71, 110,
+ 149, 232, 210, 173, 26, 214, 216, 215, 34, 72, 122, 34, 248, 148, 85,
+ 52, 117, 35, 92, 184, 42, 11, 43, 186, 20, 133, 212, 15, 123, 252,
+ 248, 205, 235, 181, 22, 41, 67, 214, 253, 28, 135, 90, 226, 18, 121,
+ 50, 36, 210, 10, 205, 175, 135, 46, 218, 209, 221, 145, 254, 253, 193,
+ 19, 72, 18, 23, 242, 121, 142, 236, 86, 7, 223, 188, 55, 98, 193,
+ 143, 51, 81, 87, 11, 245, 82, 243, 106, 233, 157, 215, 96, 229, 110,
+ 66, 69, 18, 122, 206, 223, 194, 230, 140, 80, 31, 225, 240, 245, 126,
+ 148, 149, 36, 38, 3, 42, 233, 246, 101, 14, 221, 3, 199, 196, 71,
+ 101, 159, 27, 208, 52, 153, 233, 152, 184, 13, 214, 122, 14, 21, 238,
+ 126, 243, 165, 224, 199, 198, 93, 16, 204, 13, 73, 103, 149, 42, 42,
+ 140, 189, 169, 38, 158, 67, 209, 117, 88, 177, 36, 156, 118, 83, 65,
+ 102, 252, 83, 97, 93, 4, 205, 84, 111, 124, 166, 12, 65, 3, 134,
+ 218, 244, 147, 3, 23, 237, 198, 251, 15, 114, 202, 104, 239, 155, 233,
+ 43, 236, 15, 115, 10, 240, 135, 6, 25, 206, 52, 132, 39, 213, 126,
+ 182, 65, 115, 253, 200, 205, 195, 255, 194, 226, 128, 234, 14, 226, 246,
+ 122, 227, 138, 123, 64, 230, 77, 196, 207, 23, 4, 198, 155, 238, 185,
+ 208, 123, 48, 219, 11, 149, 137, 80, 161, 93, 149, 12, 23, 241, 49,
+ 63, 133, 72, 170, 77, 22, 40, 16, 6, 4, 201, 132, 227, 144, 51,
+ 177, 91, 130, 77, 169, 185, 87, 244, 28, 232, 98, 242, 93, 71, 226,
+ 55, 105, 244, 208, 12, 95, 238, 249, 189, 141, 198, 157, 46, 191, 73,
+ 67, 120, 191, 79, 224, 240, 234, 146, 101, 93, 222, 162, 31, 11, 94,
+ 255, 161, 151, 144, 85, 34, 170, 100, 60, 115, 40, 13, 141, 202, 18,
+ 251, 87, 23, 133, 142, 168, 224, 241, 198, 6, 175, 177, 57, 251, 86,
+ 9, 68, 125, 164, 83, 104, 98, 140, 162, 66, 239, 195, 39, 202, 80,
+ 170, 111, 87, 223, 100, 107, 249, 68, 208, 175, 4, 204, 177, 126, 76,
+ 185, 88, 166, 134, 48, 29, 114, 64, 144, 125, 63, 136, 253, 164, 184,
+ 60, 120, 119, 89, 255, 20, 162, 122, 132, 49, 66, 132, 108, 43, 176,
+ 121, 60, 105, 95, 130, 159, 250, 220, 105, 25, 205, 215, 96, 128, 66,
+ 178, 205, 108, 78, 72, 30, 214, 250, 120, 189, 88, 83, 208, 172, 127,
+ 44, 51, 227, 179, 186, 214, 215, 62, 146, 199, 216, 116, 221, 111, 91,
+ 56, 198, 90, 145, 155, 136, 114, 69, 212, 59, 148, 23, 151, 132, 217,
+ 157, 75, 102, 90, 254, 128, 63, 35, 13, 91, 64, 126, 83, 162, 92,
+ 49, 223, 126, 142, 120, 149, 128, 205, 251, 245, 231, 65, 113, 19, 18,
+ 100, 54, 166, 41, 250, 7, 45, 223, 116, 36, 205, 88, 222, 156, 183,
+ 181, 53, 216, 22, 214, 158, 197, 49, 137, 96, 189, 20, 24, 22, 65,
+ 245, 165, 23, 39, 128, 67, 99, 218, 101, 186, 101, 119, 73, 209, 177,
+ 192, 132, 2, 197, 168, 197, 87, 140, 209, 25, 42, 188, 66, 194, 150,
+ 26, 22, 65, 128, 253, 46, 255, 109, 149, 220, 112, 88, 83, 84, 169,
+ 239, 214, 241, 237, 253, 71, 244, 177, 131, 253, 53, 239, 109, 235, 134,
+ 114, 136, 80, 105, 136, 148, 86, 197, 243, 77, 159, 186, 33, 140, 188,
+ 192, 150, 108, 119, 231, 109, 228, 44, 231, 84, 207, 56, 237, 177, 253,
+ 4, 69, 167, 133, 211, 34, 80, 11, 57, 40, 79, 14, 226, 88, 223,
+ 144, 28, 21, 204, 215, 193, 57, 133, 198, 133, 133, 238, 157, 39, 67,
+ 194, 25, 141, 244, 149, 130, 117, 148, 52, 28, 254, 170, 153, 100, 25,
+ 180, 33, 99, 110, 68, 251, 181, 247, 164, 46, 214, 146, 151, 35, 125,
+ 217, 66, 154, 145, 162, 28, 244, 90, 99, 159, 114, 115, 233, 91, 169,
+ 127, 52, 208, 174, 26, 204, 144, 186, 79, 193, 126, 103, 35, 146, 38,
+ 76, 14, 59, 231, 125, 76, 58, 227, 244, 51, 47, 195, 61, 175, 207,
+ 77, 97, 65, 116, 148, 142, 72, 126, 61, 122, 34, 229, 105, 41, 220,
+ 163, 129, 12, 212, 228, 238, 110, 132, 9, 108, 223, 190, 6, 32, 83,
+ 211, 112, 86, 223, 177, 159, 194, 96, 29, 48, 101, 94, 93, 30, 191,
+ 126, 123, 34, 15, 19, 195, 23, 131, 71, 169, 101, 100, 12, 79, 38,
+ 206, 68, 239, 77, 227, 133, 98, 108, 108, 216, 32, 139, 200, 71, 252,
+ 192, 120, 108, 45, 198, 208, 131, 64, 145, 152, 144, 204, 203, 168, 191,
+ 35, 135, 99, 168, 215, 136, 91, 62, 28, 89, 126, 36, 166, 67, 231,
+ 32, 70, 219, 43, 109, 176, 237, 133, 172, 22, 42, 207, 8, 205, 199,
+ 130, 109, 115, 62, 2, 148, 224, 58, 15, 200, 216, 144, 223, 222, 243,
+ 157, 178, 227, 193, 182, 247, 36, 235, 124, 206, 245, 250, 144, 153, 195,
+ 245, 220, 88, 109, 76, 242, 247, 215, 98, 241, 55, 77, 40, 213, 189,
+ 196, 39, 5, 212, 100, 150, 175, 249, 106, 185, 109, 70, 222, 175, 175,
+ 241, 68, 84, 79, 121, 195, 246, 0, 197, 90, 191, 222, 37, 236, 137,
+ 205, 167, 222, 107, 23, 19, 72, 235, 203, 216, 11, 68, 186, 99, 70,
+ 179, 122, 117, 12, 131, 175, 100, 170, 220, 212, 26, 140, 220, 17, 220,
+ 177, 120, 148, 197, 81, 175, 180, 34, 144, 147, 212, 93, 45, 101, 156,
+ 115, 63, 186, 113, 53, 150, 146, 246, 91, 254, 137, 54, 7, 66, 202,
+ 151, 118, 181, 160, 1, 119, 75, 150, 167, 134, 117, 235, 45, 65, 227,
+ 217, 95, 51, 66, 38, 77, 130, 15, 188, 187, 144, 115, 26, 30, 138,
+ 50, 71, 4, 102, 245, 81, 208, 114, 51, 212, 225, 95, 16, 27, 43,
+ 10, 167, 37, 85, 95, 137, 24, 253, 152, 161, 47, 164, 116, 59, 120,
+ 178, 226, 147, 132, 89, 185, 20, 178, 237, 185, 28, 8, 27, 143, 230,
+ 115, 143, 150, 191, 177, 13, 2, 194, 196, 6, 25, 158, 237, 35, 53,
+ 41, 173, 185, 74, 245, 100, 164, 143, 41, 194, 88, 228, 5, 231, 35,
+ 121, 177, 83, 159, 72, 20, 79, 166, 44, 49, 38, 10, 61, 173, 104,
+ 233, 147, 104, 201, 174, 42, 230, 33, 93, 70, 251, 204, 232, 53, 70,
+ 193, 146, 28, 249, 73, 35, 145, 76, 0, 209, 44, 255, 250, 109, 182,
+ 135, 133, 180, 97, 17, 21, 158, 129, 190, 120, 58, 209, 105, 50, 179,
+ 134, 174, 115, 43, 97, 82, 35, 151, 46, 16, 189, 185, 222, 202, 188,
+ 252, 70, 19, 91, 117, 83, 13, 95, 242, 11, 218, 45, 203, 160, 235,
+ 250, 4, 133, 225, 151, 143, 19, 161, 139, 237, 152, 33, 209, 138, 50,
+ 253, 148, 74, 15, 154, 235, 39, 171, 136, 217, 85, 50, 140, 16, 239,
+ 75, 172, 247, 35, 27, 197, 12, 73, 225, 43, 248, 10, 68, 40, 85,
+ 146, 151, 171, 172, 182, 175, 8, 140, 251, 126, 153, 75, 65, 184, 93,
+ 23, 194, 118, 161, 76, 20, 243, 75, 221, 106, 136, 96, 54, 10, 146,
+ 237, 149, 251, 120, 41, 43, 214, 79, 145, 195, 111, 166, 122, 119, 239,
+ 65, 131, 55, 30, 152, 60, 54, 190, 74, 19, 90, 215, 74, 67, 32,
+ 140, 251, 244, 161, 40, 157, 107, 4, 82, 227, 97, 162, 114, 69, 110,
+ 124, 138, 164, 12, 242, 252, 219, 162, 195, 227, 182, 55, 78, 72, 100,
+ 179, 82, 151, 160, 117, 188, 115, 118, 213, 89, 92, 92, 228, 5, 88,
+ 77, 168, 70, 80, 254, 215, 103, 147, 89, 76, 5, 31, 30, 222, 49,
+ 144, 226, 113, 139, 22, 93, 205, 162, 84, 195, 16, 221, 229, 37, 212,
+ 208, 151, 218, 61, 40, 81, 88, 69, 175, 101, 168, 183, 86, 115, 91,
+ 62, 174, 122, 169, 174, 113, 81, 142, 175, 109, 228, 139, 122, 120, 218,
+ 238, 10, 70, 53, 129, 142, 166, 76, 187, 168, 251, 220, 194, 241, 124,
+ 159, 6, 67, 110, 104, 240, 80, 6, 148, 193, 32, 117, 123, 97, 97,
+ 43, 239, 89, 105, 119, 51, 142, 251, 39, 210, 197, 40, 81, 239, 218,
+ 154, 180, 216, 242, 172, 55, 106, 197, 132, 80, 161, 106, 228, 213, 8,
+ 69, 203, 136, 211, 94, 135, 231, 143, 73, 85, 59, 190, 132, 13, 211,
+ 227, 176, 49, 14, 234, 244, 103, 56, 40, 190, 84, 115, 242, 207, 176,
+ 108, 219, 225, 239, 214, 26, 92, 207, 100, 119, 204, 38, 126, 199, 99,
+ 37, 146, 7, 185, 112, 30, 84, 221, 153, 29, 28, 232, 208, 247, 247,
+ 39, 83, 88, 87, 93, 207, 61, 89, 240, 187, 179, 179, 169, 110, 184,
+ 40, 54, 124, 105, 194, 83, 163, 49, 170, 116, 81, 143, 109, 253, 158,
+ 111, 6, 189, 56, 151, 0, 154, 182, 216, 134, 83, 12, 165, 58, 3,
+ 212, 95, 54, 227, 233, 147, 144, 238, 35, 249, 217, 91, 150, 164, 96,
+ 238, 157, 31, 223, 73, 92, 137, 10, 229, 11, 211, 105, 27, 250, 9,
+ 239, 184, 137, 155, 184, 211, 6, 199, 137, 187, 199, 221, 46, 215, 176,
+ 137, 71, 16, 62, 10, 107, 84, 106, 223, 75, 108, 203, 35, 247, 78,
+ 196, 99, 28, 31, 217, 242, 139, 186, 128, 150, 110, 151, 87, 90, 109,
+ 54, 129, 106, 193, 194, 88, 115, 189, 118, 225, 6, 231, 180, 43, 142,
+ 110, 21, 2, 141, 221, 144, 179, 82, 151, 188, 121, 248, 77, 143, 215,
+ 143, 10, 182, 188, 186, 208, 82, 215, 60, 18, 196, 185, 159, 68, 68,
+ 201, 207, 74, 82, 145, 59, 149, 16, 63, 201, 13, 17, 244, 71, 194,
+ 197, 191, 95, 40, 252, 225, 179, 165, 137, 169, 161, 135, 36, 151, 106,
+ 171, 138, 236, 185, 45, 131, 92, 220, 225, 18, 78, 251, 98, 102, 21,
+ 22, 194, 152, 194, 48, 164, 210, 60, 201, 23, 120, 207, 71, 209, 236,
+ 222, 86, 217, 166, 220, 146, 211, 247, 80, 246, 155, 73, 111, 145, 122,
+ 227, 119, 103, 180, 85, 100, 168, 211, 204, 80, 168, 72, 152, 79, 110,
+ 250, 162, 254, 120, 200, 77, 60, 156, 218, 132, 20, 86, 169, 200, 171,
+ 69, 33, 104, 117, 121, 41, 217, 97, 225, 125, 66, 58, 39, 159, 93,
+ 234, 184, 240, 229, 16, 82, 49, 68, 209, 135, 209, 158, 15, 6, 211,
+ 218, 202, 14, 28, 39, 226, 234, 26, 209, 114, 217, 193, 154, 233, 199,
+ 150, 162, 250, 193, 114, 201, 37, 84, 186, 74, 90, 56, 3, 126, 34,
+ 215, 195, 73, 87, 30, 186, 10, 38, 212, 181, 39, 132, 189, 109, 75,
+ 73, 123, 136, 186, 242, 118, 38, 128, 222, 79, 220, 70, 161, 246, 34,
+ 54, 170, 241, 2, 205, 224, 218, 64, 251, 90, 3, 207, 83, 162, 143,
+ 75, 131, 108, 172, 193, 152, 114, 120, 37, 14, 205, 232, 54, 40, 131,
+ 88, 118, 164, 177, 200, 248, 184, 77, 56, 55, 24, 102, 120, 46, 240,
+ 204, 139, 202, 29, 226, 230, 240, 71, 166, 39, 8, 64, 238, 173, 171,
+ 122, 210, 134, 8, 250, 50, 141, 14, 21, 9, 203, 131, 132, 150, 29,
+ 22, 129, 148, 226, 141, 43, 61, 214, 237, 14, 33, 152, 180, 21, 99,
+ 98, 99, 171, 222, 38, 80, 222, 39, 169, 2, 47, 141, 17, 23, 53,
+ 83, 18, 90, 10, 84, 180, 53, 180, 241, 12, 186, 39, 92, 80, 8,
+ 81, 163, 95, 210, 77, 179, 183, 248, 58, 236, 193, 91, 8, 131, 25,
+ 167, 80, 36, 217, 0, 177, 49, 195, 90, 161, 47, 90, 237, 213, 72,
+ 36, 91, 15, 165, 14, 10, 63, 49, 109, 204, 113, 179, 217, 135, 88,
+ 197, 151, 48, 167, 165, 151, 123, 212, 194, 25, 234, 110, 78, 100, 25,
+ 249, 13, 187, 65, 98, 239, 73, 250, 30, 42, 20, 250, 73, 188, 243,
+ 18, 95, 211, 146, 62, 215, 84, 84, 160, 190, 72, 17, 245, 110, 159,
+ 195, 23, 179, 94, 146, 26, 41, 215, 45, 210, 75, 155, 104, 208, 172,
+ 117, 84, 68, 155, 231, 168, 8, 34, 104, 17, 171, 17, 230, 179, 206,
+ 33, 31, 154, 141, 46, 24, 15, 212, 250, 50, 72, 45, 125, 195, 230,
+ 5, 84, 37, 63, 78, 45, 104, 178, 162, 57, 72, 130, 103, 140, 242,
+ 208, 196, 235, 19, 46, 235, 137, 141, 218, 228, 173, 74, 223, 248, 168,
+ 221, 12, 88, 231, 197, 113, 187, 186, 236, 189, 225, 199, 91, 17, 109,
+ 154, 234, 163, 146, 43, 249, 156, 119, 30, 171, 213, 210, 145, 176, 199,
+ 191, 52, 111, 16, 122, 18, 117, 10, 185, 106, 251, 15, 167, 208, 51,
+ 250, 93, 192, 86, 190, 254, 205, 252, 60, 211, 197, 138, 19, 166, 69,
+ 66, 217, 39, 24, 250, 95, 50, 145, 63, 45, 25, 99, 72, 80, 16,
+ 149, 73, 110, 209, 111, 175, 136, 68, 225, 88, 32, 177, 53, 51, 202,
+ 14, 96, 108, 14, 210, 156, 246, 137, 249, 177, 97, 107, 157, 92, 29,
+ 85, 97, 52, 121, 237, 57, 37, 70, 142, 53, 122, 43, 125, 142, 163,
+ 201, 175, 236, 214, 64, 53, 177, 233, 182, 69, 246, 202, 45, 147, 102,
+ 226, 219, 174, 46, 161, 15, 168, 241, 212, 139, 14, 163, 145, 184, 53,
+ 155, 234, 253, 42, 88, 9, 202, 166, 52, 123, 204, 42, 243, 14, 253,
+ 235, 91, 29, 146, 51, 134, 115, 142, 133, 159, 174, 221, 187, 62, 110,
+ 68, 190, 229, 243, 134, 243, 232, 197, 222, 5, 134, 18, 18, 250, 37,
+ 81, 190, 210, 131, 97, 119, 145, 59, 195, 196, 7, 146, 228, 120, 66,
+ 199, 178, 7, 143, 245, 38, 142, 92, 4, 228, 195, 184, 143, 197, 166,
+ 166, 114, 212, 246, 146, 34, 194, 199, 218, 136, 197, 202, 142, 194, 42,
+ 103, 37, 76, 75, 37, 174, 95, 205, 155, 247, 71, 101, 240, 147, 208,
+ 187, 222, 92, 99, 229, 83, 253, 146, 138, 212, 158, 64, 148, 63, 204,
+ 212, 245, 73, 196, 51, 158, 26, 17, 212, 57, 90, 199, 164, 210, 202,
+ 113, 242, 169, 183, 88, 70, 162, 24, 155, 199, 85, 242, 34, 134, 73,
+ 235, 8, 47, 29, 177, 101, 31, 149, 107, 116, 176, 213, 198, 142, 229,
+ 148, 84, 99, 14, 17, 107, 248, 170, 171, 122, 83, 10, 42, 172, 154,
+ 149, 174, 53, 100, 5, 84, 208, 26, 237, 122, 57, 71, 152, 214, 151,
+ 51, 73, 111, 93, 117, 239, 214, 220, 181, 186, 147, 134, 108, 88, 71,
+ 76, 107, 66, 179, 115, 59, 101, 35, 24, 59, 193, 36, 50, 52, 94,
+ 22, 105, 101, 128, 128, 162, 144, 81, 46, 54, 226, 208, 89, 159, 7,
+ 17, 143, 215, 203, 80, 242, 171, 185, 146, 76, 59, 6, 118, 181, 175,
+ 187, 191, 40, 47, 146, 33, 150, 147, 3, 87, 106, 56, 50, 193, 252,
+ 158, 101, 150, 60, 2, 26, 191, 254, 145, 233, 5, 201, 175, 252, 185,
+ 58, 10, 21, 20, 24, 95, 102, 211, 7, 83, 218, 98, 175, 96, 16,
+ 87, 88, 80, 211, 134, 77, 248, 220, 147, 148, 231, 80, 203, 162, 83,
+ 229, 228, 189, 26, 152, 84, 177, 244, 180, 184, 125, 190, 36, 220, 100,
+ 142, 208, 179, 4, 115, 96, 140, 13, 57, 8, 165, 137, 72, 180, 113,
+ 224, 246, 64, 149, 193, 10, 30, 105, 188, 49, 50, 219, 126, 80, 4,
+ 127, 64, 152, 254, 167, 22, 207, 189, 168, 109, 241, 194, 180, 108, 83,
+ 132, 161, 117, 71, 60, 22, 63, 4, 191, 237, 205, 126, 244, 206, 243,
+ 115, 56, 16, 122, 235, 230, 248, 35, 174, 30, 82, 10, 170, 172, 229,
+ 155, 185, 37, 72, 132, 174, 97, 40, 177, 45, 188, 168, 87, 228, 167,
+ 201, 208, 236, 113, 5, 155, 179, 216, 159, 135, 102, 249, 214, 200, 182,
+ 183, 124, 51, 147, 42, 107, 194, 68, 98, 101, 110, 118, 160, 13, 107,
+ 193, 117, 110, 233, 28, 195, 156, 84, 91, 157, 176, 251, 202, 234, 88,
+ 49, 97, 140, 247, 165, 208, 214, 6, 201, 231, 50, 3, 7, 155, 33,
+ 93, 197, 85, 23, 147, 236, 76, 217, 91, 133, 119, 44, 24, 141, 137,
+ 99, 96, 13, 242, 235, 185, 160, 214, 202, 10, 23, 226, 135, 183, 139,
+ 155, 102, 231, 250, 55, 134, 213, 244, 77, 116, 53, 99, 253, 153, 7,
+ 100, 163, 62, 248, 5, 186, 180, 183, 30, 221, 98, 66, 195, 31, 175,
+ 183, 171, 201, 98, 40, 246, 23, 180, 46, 184, 175, 92, 45, 173, 169,
+ 112, 206, 180, 87, 52, 231, 250, 83, 90, 39, 122, 239, 221, 108, 45,
+ 20, 61, 61, 163, 103, 252, 155, 17, 60, 51, 29, 43, 61, 248, 53,
+ 129, 109, 106, 116, 117, 15, 13, 118, 144, 79, 176, 114, 86, 95, 53,
+ 188, 44, 207, 12, 184, 78, 53, 132, 59, 34, 248, 117, 137, 170, 255,
+ 243, 123, 181, 16, 110, 20, 247, 130, 29, 38, 216, 157, 103, 230, 61,
+ 154, 147, 139, 36, 242, 197, 136, 10, 15, 219, 37, 79, 161, 195, 243,
+ 170, 152, 217, 172, 111, 26, 2, 162, 140, 94, 20, 191, 67, 53, 10,
+ 159, 212, 102, 31, 186, 189, 31, 133, 63, 82, 212, 66, 212, 159, 104,
+ 33, 109, 19, 158, 214, 87, 100, 99, 217, 48, 187, 248, 116, 192, 65,
+ 196, 184, 35, 143, 170, 199, 44, 47, 122, 139, 181, 24, 215, 196, 240,
+ 157, 12, 149, 85, 232, 10, 58, 199, 173, 46, 59, 196, 52, 243, 130,
+ 152, 106, 229, 121, 113, 137, 125, 203, 230, 161, 55, 181, 209, 24, 151,
+ 80, 234, 136, 162, 35, 148, 198, 8, 39, 93, 30, 220, 65, 37, 214,
+ 252, 38, 141, 168, 16, 78, 154, 204, 207, 121, 10, 153, 134, 61, 245,
+ 83, 251, 74, 139, 90, 55, 171, 249, 241, 20, 42, 61, 62, 120, 53,
+ 148, 229, 70, 28, 41, 141, 92, 108, 17, 245, 110, 20, 101, 60, 238,
+ 169, 11, 71, 198, 251, 108, 221, 248, 135, 77, 78, 78, 56, 233, 36,
+ 205, 46, 14, 38, 38, 248, 229, 244, 136, 76, 234, 18, 247, 205, 197,
+ 118, 197, 170, 40, 174, 242, 95, 189, 239, 143, 59, 106, 95, 205, 184,
+ 56, 223, 227, 115, 218, 207, 23, 11, 213, 146, 103, 88, 78, 180, 87,
+ 190, 80, 63, 209, 241, 32, 98, 28, 50, 243, 48, 12, 116, 129, 50,
+ 244, 26, 10, 66, 141, 118, 87, 13, 123, 110, 112, 72, 114, 45, 158,
+ 191, 69, 168, 137, 177, 143, 54, 25, 102, 56, 122, 45, 182, 74, 126,
+ 159, 103, 156, 203, 51, 104, 82, 24, 173, 54, 61, 3, 77, 68, 161,
+ 121, 75, 184, 251, 228, 213, 186, 184, 247, 220, 44, 37, 66, 196, 241,
+ 216, 182, 243, 144, 8, 94, 95, 29, 149, 3, 77, 9, 149, 7, 69,
+ 190, 14, 103, 81, 63, 118, 105, 52, 2, 181, 248, 244, 228, 64, 249,
+ 195, 33, 211, 10, 25, 151, 134, 0, 136, 228, 128, 108, 11, 199, 124,
+ 38, 27, 247, 252, 37, 202, 198, 21, 217, 91, 228, 50, 137, 147, 171,
+ 234, 90, 193, 17, 163, 107, 253, 219, 23, 191, 13, 81, 16, 20, 163,
+ 206, 102, 239, 122, 239, 86, 86, 59, 247, 190, 154, 243, 39, 38, 108,
+ 82, 154, 11, 166, 38, 55, 96, 41, 173, 14, 44, 244, 33, 187, 77,
+ 114, 141, 80, 233, 176, 40, 99, 235, 205, 147, 53, 218, 230, 249, 219,
+ 28, 212, 23, 189, 187, 204, 119, 231, 179, 139, 242, 159, 248, 35, 145,
+ 137, 146, 215, 250, 28, 218, 229, 21, 54, 239, 105, 151, 60, 236, 52,
+ 148, 108, 51, 173, 64, 69, 216, 98, 42, 185, 36, 90, 41, 115, 113,
+ 162, 120, 91, 184, 107, 173, 88, 199, 91, 52, 13, 50, 108, 250, 70,
+ 182, 210, 162, 52, 36, 153, 43, 205, 27, 27, 169, 81, 223, 189, 95,
+ 34, 205, 168, 68, 91, 212, 157, 37, 232, 47, 234, 204, 35, 239, 173,
+ 143, 241, 241, 80, 54, 96, 133, 56, 56, 193, 136, 246, 74, 249, 64,
+ 183, 226, 165, 237, 149, 43, 153, 172, 17, 215, 159, 27, 187, 183, 200,
+ 248, 170, 191, 208, 52, 143, 97, 73, 15, 84, 17, 187, 147, 214, 131,
+ 80, 204, 36, 130, 42, 135, 115, 1, 3, 169, 227, 213, 24, 75, 1,
+ 75, 204, 133, 226, 39, 1, 85, 145, 232, 65, 122, 246, 152, 142, 174,
+ 104, 36, 43, 55, 153, 248, 67, 87, 133, 81, 89, 105, 99, 25, 164,
+ 158, 199, 173, 240, 83, 214, 214, 188, 62, 215, 22, 114, 129, 86, 62,
+ 156, 118, 73, 149, 5, 18, 136, 62, 255, 204, 150, 190, 81, 131, 227,
+ 154, 63, 189, 47, 210, 26, 57, 102, 129, 171, 28, 45, 255, 189, 2,
+ 200, 221, 130, 112, 182, 12, 191, 153, 220, 254, 86, 133, 95, 147, 221,
+ 66, 255, 100, 61, 166, 223, 183, 115, 200, 47, 195, 34, 166, 250, 88,
+ 77, 36, 185, 140, 89, 136, 83, 195, 185, 188, 162, 62, 245, 112, 186,
+ 217, 15, 169, 32, 162, 27, 206, 71, 227, 93, 54, 188, 191, 226, 44,
+ 28, 118, 145, 180, 152, 192, 36, 155, 229, 147, 123, 183, 242, 94, 141,
+ 176, 17, 57, 153, 97, 111, 112, 235, 99, 60, 95, 156, 206, 220, 60,
+ 170, 26, 189, 62, 253, 118, 105, 91, 228, 237, 130, 25, 45, 177, 137,
+ 170, 139, 156, 250, 153, 100, 108, 183, 52, 53, 77, 155, 174, 11, 60,
+ 153, 91, 72, 219, 38, 113, 187, 90, 74, 171, 47, 183, 159, 18, 26,
+ 53, 70, 102, 125, 109, 59, 155, 63, 249, 219, 57, 55, 232, 41, 99,
+ 182, 244, 151, 75, 83, 82, 171, 186, 111, 167, 107, 211, 40, 74, 89,
+ 167, 216, 203, 184, 175, 182, 108, 238, 34, 37, 148, 127, 155, 54, 74,
+ 52, 15, 177, 178, 193, 206, 53, 216, 231, 200, 52, 201, 202, 118, 64,
+ 21, 74, 184, 127, 84, 149, 203, 16, 104, 236, 159, 206, 199, 27, 195,
+ 205, 32, 73, 226, 53, 137, 46, 210, 31, 160, 235, 95, 106, 42, 65,
+ 119, 163, 217, 169, 189, 173, 92, 218, 99, 91, 173, 242, 121, 126, 107,
+ 90, 60, 183, 142, 194, 183, 141, 182, 112, 49, 205, 138, 30, 166, 201,
+ 193, 134, 221, 207, 89, 243, 247, 31, 84, 239, 179, 137, 71, 122, 102,
+ 237, 89, 148, 85, 205, 80, 63, 115, 160, 83, 183, 102, 160, 74, 30,
+ 15, 18, 23, 214, 169, 53, 113, 195, 252, 188, 51, 26, 142, 21, 184,
+ 159, 127, 183, 165, 113, 139, 237, 235, 210, 163, 80, 181, 176, 193, 2,
+ 87, 229, 48, 199, 145, 185, 133, 172, 250, 163, 247, 47, 148, 239, 60,
+ 98, 180, 226, 72, 229, 25, 80, 48, 125, 169, 95, 119, 216, 245, 201,
+ 6, 99, 120, 174, 208, 33, 23, 71, 61, 163, 136, 21, 194, 151, 189,
+ 149, 89, 227, 61, 201, 245, 52, 215, 63, 155, 133, 225, 85, 219, 43,
+ 253, 76, 21, 250, 57, 155, 34, 61, 167, 161, 55, 143, 90, 108, 21,
+ 80, 236, 173, 162, 133, 40, 62, 228, 47, 52, 82, 169, 210, 233, 220,
+ 185, 200, 87, 46, 60, 162, 51, 199, 230, 22, 208, 25, 90, 113, 224,
+ 220, 197, 46, 230, 139, 162, 38, 39, 56, 223, 167, 41, 27, 23, 200,
+ 207, 234, 89, 34, 146, 243, 94, 198, 229, 227, 151, 231, 143, 33, 116,
+ 188, 67, 47, 60, 225, 82, 129, 97, 101, 219, 214, 91, 143, 10, 217,
+ 234, 108, 25, 195, 181, 134, 166, 108, 109, 174, 221, 60, 234, 144, 27,
+ 187, 114, 17, 185, 77, 72, 244, 107, 238, 139, 36, 234, 134, 105, 210,
+ 59, 106, 237, 16, 251, 59, 102, 167, 128, 75, 66, 59, 230, 110, 163,
+ 99, 140, 23, 58, 82, 170, 231, 140, 18, 38, 54, 30, 149, 177, 182,
+ 79, 76, 77, 170, 181, 29, 93, 19, 109, 109, 97, 186, 40, 192, 247,
+ 34, 176, 163, 195, 176, 44, 248, 116, 192, 246, 107, 159, 129, 131, 44,
+ 97, 131, 4, 123, 253, 248, 158, 103, 9, 71, 115, 68, 226, 230, 103,
+ 238, 144, 54, 122, 191, 221, 165, 201, 186, 194, 15, 250, 248, 119, 227,
+ 229, 70, 139, 68, 59, 76, 239, 36, 9, 29, 152, 32, 96, 113, 249,
+ 163, 206, 132, 33, 222, 29, 208, 72, 20, 145, 67, 86, 200, 73, 250,
+ 102, 213, 172, 74, 182, 175, 28, 191, 165, 124, 82, 105, 213, 227, 163,
+ 185, 199, 98, 130, 16, 233, 157, 124, 235, 189, 206, 157, 123, 197, 209,
+ 237, 197, 101, 197, 165, 206, 251, 205, 85, 222, 56, 87, 174, 206, 151,
+ 224, 162, 93, 119, 205, 185, 130, 142, 242, 238, 17, 218, 77, 234, 124,
+ 71, 115, 146, 25, 90, 220, 40, 28, 137, 27, 21, 230, 147, 1, 125,
+ 183, 162, 27, 219, 165, 104, 195, 89, 204, 172, 189, 170, 154, 243, 158,
+ 37, 172, 117, 60, 150, 192, 113, 189, 137, 112, 251, 221, 221, 107, 135,
+ 99, 195, 153, 3, 60, 113, 242, 150, 101, 173, 33, 66, 2, 155, 122,
+ 165, 49, 183, 33, 110, 67, 134, 72, 221, 112, 130, 85, 117, 242, 113,
+ 133, 190, 169, 177, 102, 119, 3, 99, 86, 63, 22, 73, 205, 35, 133,
+ 228, 67, 190, 62, 193, 59, 31, 110, 118, 197, 248, 162, 179, 150, 63,
+ 120, 149, 60, 230, 67, 192, 59, 61, 103, 168, 152, 129, 5, 105, 187,
+ 19, 212, 210, 81, 111, 184, 198, 172, 105, 176, 93, 161, 140, 207, 81,
+ 154, 88, 17, 118, 223, 223, 158, 231, 175, 9, 182, 154, 124, 157, 88,
+ 112, 95, 110, 211, 68, 56, 227, 50, 111, 10, 74, 218, 94, 43, 250,
+ 11, 49, 75, 209, 49, 58, 21, 218, 47, 244, 246, 120, 143, 146, 5,
+ 166, 6, 17, 51, 232, 109, 252, 230, 185, 43, 94, 164, 217, 217, 134,
+ 88, 168, 11, 81, 171, 32, 76, 55, 200, 248, 135, 74, 224, 199, 179,
+ 169, 26, 7, 26, 71, 45, 246, 124, 154, 109, 205, 21, 226, 178, 92,
+ 212, 151, 18, 121, 147, 175, 195, 122, 201, 245, 118, 36, 173, 16, 141,
+ 244, 92, 134, 62, 210, 219, 8, 106, 125, 65, 163, 153, 185, 201, 148,
+ 10, 111, 131, 2, 204, 150, 200, 8, 68, 225, 0, 203, 143, 49, 180,
+ 19, 88, 84, 15, 60, 34, 250, 21, 67, 139, 98, 136, 66, 235, 190,
+ 220, 221, 90, 77, 108, 66, 35, 56, 140, 22, 12, 56, 33, 233, 149,
+ 89, 143, 127, 216, 250, 249, 74, 228, 242, 71, 52, 91, 61, 230, 103,
+ 195, 150, 121, 82, 57, 20, 222, 3, 244, 108, 46, 119, 230, 42, 11,
+ 173, 253, 4, 55, 51, 35, 6, 142, 205, 210, 175, 84, 13, 200, 23,
+ 54, 187, 20, 226, 87, 127, 54, 162, 28, 12, 74, 191, 122, 151, 177,
+ 16, 73, 221, 140, 80, 149, 87, 154, 141, 234, 221, 53, 49, 109, 219,
+ 216, 151, 142, 4, 40, 2, 134, 181, 183, 223, 55, 23, 215, 229, 166,
+ 249, 250, 143, 82, 216, 143, 20, 80, 82, 209, 119, 101, 100, 45, 32,
+ 161, 234, 119, 217, 11, 17, 94, 144, 156, 215, 165, 24, 78, 233, 173,
+ 21, 125, 140, 218, 166, 231, 225, 59, 17, 48, 111, 220, 19, 206, 33,
+ 89, 128, 104, 68, 23, 49, 218, 130, 115, 187, 116, 253, 86, 8, 62,
+ 153, 239, 133, 226, 18, 223, 119, 234, 118, 234, 218, 132, 110, 193, 77,
+ 15, 162, 232, 133, 115, 146, 2, 60, 122, 147, 159, 73, 217, 126, 68,
+ 186, 168, 130, 96, 37, 165, 210, 116, 229, 169, 168, 196, 61, 249, 124,
+ 43, 86, 149, 28, 205, 167, 49, 54, 250, 238, 144, 242, 71, 159, 56,
+ 217, 117, 142, 55, 237, 239, 31, 27, 167, 102, 124, 107, 77, 110, 138,
+ 169, 230, 124, 234, 194, 91, 167, 86, 148, 186, 196, 48, 82, 12, 205,
+ 207, 107, 174, 180, 92, 99, 159, 98, 87, 215, 222, 205, 126, 194, 255,
+ 16, 181, 40, 157, 193, 222, 195, 218, 142, 131, 204, 114, 111, 143, 78,
+ 147, 241, 179, 4, 250, 137, 56, 115, 60, 49, 153, 134, 35, 206, 51,
+ 146, 65, 59, 206, 167, 225, 239, 217, 174, 222, 143, 9, 191, 113, 23,
+ 85, 246, 196, 86, 56, 223, 222, 246, 20, 138, 222, 83, 233, 97, 201,
+ 209, 186, 138, 47, 143, 235, 67, 88, 188, 178, 203, 225, 155, 109, 41,
+ 92, 108, 18, 219, 170, 119, 91, 255, 99, 104, 251, 129, 150, 78, 111,
+ 166, 225, 198, 189, 182, 155, 219, 91, 116, 29, 174, 183, 187, 2, 28,
+ 119, 238, 149, 8, 115, 34, 238, 92, 81, 188, 132, 18, 69, 26, 22,
+ 239, 112, 215, 142, 255, 205, 187, 133, 212, 146, 121, 157, 139, 182, 42,
+ 29, 5, 26, 104, 17, 225, 194, 23, 130, 217, 203, 43, 73, 88, 9,
+ 137, 125, 48, 218, 8, 168, 238, 226, 36, 126, 102, 55, 82, 83, 235,
+ 204, 224, 120, 230, 207, 51, 179, 195, 255, 80, 234, 155, 181, 115, 169,
+ 214, 59, 197, 120, 193, 59, 72, 247, 179, 75, 221, 189, 119, 19, 57,
+ 72, 90, 11, 156, 10, 219, 143, 76, 100, 198, 179, 153, 247, 238, 87,
+ 157, 11, 123, 162, 110, 163, 99, 149, 28, 60, 242, 230, 9, 42, 151,
+ 209, 64, 216, 73, 76, 213, 210, 211, 167, 69, 41, 37, 116, 87, 202,
+ 104, 66, 22, 13, 165, 218, 122, 78, 161, 178, 197, 219, 54, 25, 88,
+ 53, 93, 209, 218, 51, 104, 146, 164, 23, 191, 242, 202, 94, 46, 207,
+ 117, 150, 54, 18, 83, 46, 195, 70, 232, 234, 19, 138, 242, 180, 22,
+ 255, 212, 162, 234, 115, 58, 216, 231, 217, 129, 108, 208, 79, 72, 219,
+ 10, 133, 63, 237, 127, 242, 154, 217, 242, 74, 8, 173, 181, 168, 190,
+ 5, 57, 212, 122, 1, 189, 169, 137, 8, 69, 57, 221, 135, 163, 36,
+ 152, 184, 103, 232, 226, 164, 167, 212, 193, 102, 211, 146, 40, 205, 142,
+ 180, 208, 122, 162, 161, 166, 49, 237, 218, 161, 247, 110, 177, 132, 178,
+ 187, 197, 5, 163, 147, 196, 158, 147, 172, 7, 235, 225, 84, 220, 12,
+ 212, 116, 111, 39, 92, 98, 70, 198, 100, 35, 194, 11, 171, 243, 187,
+ 27, 123, 158, 17, 167, 100, 76, 6, 5, 111, 138, 105, 51, 27, 238,
+ 60, 86, 181, 167, 13, 37, 65, 198, 231, 75, 44, 39, 168, 228, 114,
+ 23, 248, 12, 107, 37, 138, 187, 90, 15, 155, 182, 162, 102, 240, 30,
+ 133, 153, 169, 239, 229, 190, 209, 149, 97, 37, 109, 251, 54, 198, 127,
+ 188, 102, 125, 18, 95, 217, 83, 50, 98, 118, 190, 141, 222, 214, 81,
+ 216, 123, 189, 8, 169, 219, 166, 19, 87, 231, 186, 151, 248, 242, 80,
+ 242, 50, 191, 63, 227, 107, 250, 89, 241, 23, 40, 94, 99, 203, 148,
+ 118, 54, 28, 195, 115, 188, 242, 81, 1, 138, 129, 162, 237, 83, 130,
+ 229, 175, 149, 85, 218, 251, 58, 87, 100, 70, 9, 240, 189, 218, 82,
+ 24, 200, 199, 52, 41, 144, 102, 163, 5, 2, 142, 186, 39, 251, 47,
+ 170, 90, 63, 70, 224, 159, 144, 163, 49, 186, 231, 162, 69, 25, 50,
+ 37, 52, 42, 121, 185, 196, 111, 185, 111, 104, 15, 177, 40, 134, 249,
+ 18, 20, 177, 89, 180, 148, 113, 165, 66, 147, 1, 226, 153, 43, 148,
+ 40, 239, 200, 226, 9, 29, 41, 224, 22, 109, 156, 144, 8, 78, 239,
+ 79, 249, 20, 120, 125, 56, 178, 160, 222, 241, 80, 148, 98, 50, 131,
+ 222, 239, 114, 71, 57, 181, 201, 161, 247, 122, 112, 47, 244, 34, 163,
+ 181, 121, 86, 54, 24, 105, 48, 229, 252, 62, 110, 15, 229, 135, 57,
+ 11, 233, 193, 227, 73, 228, 200, 209, 194, 142, 200, 186, 54, 119, 36,
+ 42, 207, 243, 142, 185, 150, 177, 6, 92, 146, 46, 168, 232, 226, 36,
+ 204, 153, 124, 236, 9, 164, 35, 146, 60, 220, 33, 90, 88, 197, 244,
+ 202, 229, 210, 5, 87, 82, 100, 47, 182, 111, 98, 217, 162, 111, 11,
+ 164, 149, 16, 23, 84, 106, 25, 36, 228, 91, 223, 167, 190, 207, 167,
+ 125, 207, 53, 247, 6, 95, 4, 73, 81, 77, 219, 205, 55, 142, 74,
+ 182, 182, 119, 146, 240, 63, 177, 225, 52, 20, 189, 47, 228, 102, 21,
+ 223, 144, 182, 122, 186, 100, 216, 109, 177, 168, 114, 173, 61, 213, 215,
+ 44, 142, 205, 75, 24, 225, 50, 241, 205, 157, 130, 124, 68, 196, 128,
+ 249, 168, 163, 107, 39, 58, 230, 36, 47, 121, 31, 148, 6, 170, 86,
+ 154, 152, 48, 74, 118, 116, 197, 37, 240, 54, 62, 228, 176, 84, 99,
+ 106, 128, 18, 184, 13, 253, 234, 60, 180, 134, 21, 75, 195, 98, 52,
+ 149, 110, 210, 233, 110, 54, 81, 123, 98, 10, 124, 225, 165, 116, 47,
+ 115, 160, 147, 42, 8, 12, 137, 167, 185, 192, 115, 232, 229, 89, 202,
+ 210, 144, 142, 143, 206, 129, 36, 211, 127, 82, 148, 21, 70, 84, 202,
+ 119, 87, 139, 157, 61, 146, 5, 175, 252, 129, 240, 65, 205, 193, 163,
+ 246, 246, 97, 157, 162, 26, 135, 0, 254, 25, 136, 174, 143, 162, 35,
+ 54, 32, 113, 8, 123, 51, 128, 63, 168, 83, 74, 253, 118, 219, 99,
+ 129, 103, 186, 88, 217, 159, 175, 48, 202, 122, 112, 163, 181, 190, 136,
+ 61, 133, 148, 37, 77, 50, 46, 243, 73, 102, 16, 102, 235, 58, 35,
+ 116, 142, 106, 44, 121, 191, 45, 165, 128, 20, 23, 244, 26, 170, 95,
+ 173, 147, 134, 235, 102, 142, 127, 243, 214, 59, 231, 166, 234, 61, 83,
+ 64, 167, 80, 12, 161, 211, 207, 25, 50, 51, 187, 36, 119, 246, 61,
+ 224, 187, 146, 152, 75, 171, 218, 213, 104, 174, 78, 201, 134, 43, 203,
+ 167, 179, 180, 187, 48, 20, 99, 170, 160, 233, 167, 215, 209, 111, 216,
+ 236, 67, 220, 182, 210, 18, 163, 55, 201, 103, 39, 95, 58, 68, 50,
+ 192, 66, 167, 124, 49, 42, 90, 86, 121, 214, 156, 101, 101, 66, 251,
+ 13, 131, 105, 83, 38, 62, 165, 199, 240, 248, 66, 111, 95, 181, 84,
+ 46, 18, 106, 97, 61, 27, 182, 239, 210, 85, 15, 199, 158, 39, 5,
+ 250, 57, 157, 41, 28, 172, 180, 95, 21, 214, 226, 98, 59, 15, 28,
+ 123, 158, 9, 172, 139, 220, 227, 214, 71, 124, 94, 200, 160, 239, 218,
+ 117, 167, 150, 67, 251, 194, 158, 154, 88, 23, 67, 5, 109, 32, 91,
+ 119, 116, 1, 22, 77, 224, 253, 220, 52, 242, 133, 162, 52, 231, 210,
+ 36, 111, 117, 19, 141, 167, 151, 136, 194, 174, 119, 12, 198, 38, 29,
+ 75, 159, 136, 237, 12, 237, 82, 102, 186, 198, 52, 205, 222, 47, 247,
+ 154, 84, 73, 204, 185, 89, 175, 238, 232, 192, 202, 29, 255, 181, 198,
+ 90, 121, 244, 85, 112, 182, 84, 214, 19, 207, 135, 82, 168, 8, 202,
+ 172, 234, 11, 58, 236, 53, 218, 36, 56, 183, 220, 52, 248, 143, 34,
+ 194, 228, 244, 165, 3, 58, 185, 197, 101, 6, 230, 173, 94, 178, 5,
+ 54, 124, 66, 197, 170, 48, 94, 182, 46, 90, 248, 80, 115, 173, 84,
+ 51, 212, 155, 196, 138, 76, 147, 86, 157, 16, 147, 32, 154, 229, 128,
+ 179, 165, 59, 43, 226, 116, 168, 111, 237, 99, 222, 2, 225, 198, 59,
+ 89, 175, 39, 13, 15, 189, 44, 198, 89, 199, 43, 240, 165, 113, 154,
+ 199, 35, 138, 39, 83, 171, 61, 207, 105, 83, 169, 62, 26, 79, 240,
+ 10, 250, 64, 161, 115, 238, 21, 57, 6, 166, 3, 125, 93, 91, 212,
+ 162, 30, 90, 183, 68, 182, 149, 21, 70, 73, 125, 155, 123, 192, 12,
+ 127, 51, 223, 124, 181, 142, 3, 131, 87, 97, 254, 189, 99, 217, 209,
+ 69, 233, 161, 14, 90, 236, 193, 186, 89, 101, 180, 225, 110, 54, 212,
+ 103, 163, 247, 153, 181, 10, 107, 108, 41, 48, 204, 27, 141, 80, 25,
+ 148, 30, 143, 105, 106, 245, 123, 163, 5, 245, 47, 231, 212, 155, 243,
+ 173, 106, 108, 107, 223, 136, 165, 13, 45, 226, 234, 157, 229, 99, 176,
+ 178, 220, 153, 77, 179, 237, 224, 146, 242, 151, 48, 103, 14, 79, 58,
+ 166, 99, 140, 55, 105, 102, 62, 169, 196, 209, 202, 228, 243, 78, 174,
+ 43, 22, 64, 13, 22, 12, 232, 145, 201, 63, 48, 225, 43, 142, 41,
+ 64, 20, 140, 41, 207, 214, 113, 178, 124, 200, 210, 153, 86, 145, 209,
+ 209, 224, 197, 86, 197, 135, 18, 77, 48, 81, 140, 129, 237, 157, 98,
+ 63, 72, 93, 138, 171, 86, 22, 182, 234, 3, 201, 140, 28, 15, 13,
+ 74, 53, 17, 133, 220, 188, 94, 63, 251, 134, 73, 185, 252, 42, 113,
+ 82, 154, 182, 169, 44, 77, 1, 181, 63, 159, 110, 67, 19, 183, 175,
+ 135, 242, 163, 128, 50, 182, 42, 173, 60, 220, 121, 42, 121, 156, 15,
+ 146, 60, 82, 104, 91, 68, 227, 47, 71, 39, 207, 21, 154, 72, 107,
+ 162, 183, 18, 160, 60, 9, 173, 242, 170, 66, 195, 121, 26, 219, 36,
+ 164, 87, 167, 34, 208, 148, 188, 101, 113, 175, 157, 133, 203, 40, 80,
+ 70, 50, 36, 64, 34, 225, 100, 234, 193, 12, 164, 93, 218, 166, 27,
+ 28, 34, 4, 241, 180, 208, 216, 6, 25, 105, 107, 190, 130, 82, 8,
+ 139, 76, 34, 51, 201, 238, 219, 44, 247, 112, 13, 141, 213, 71, 110,
+ 161, 33, 93, 16, 242, 101, 173, 223, 97, 183, 189, 82, 63, 200, 194,
+ 84, 17, 217, 59, 136, 108, 161, 28, 165, 240, 58, 229, 189, 174, 76,
+ 63, 102, 199, 167, 241, 225, 151, 186, 221, 44, 26, 44, 106, 218, 247,
+ 77, 223, 214, 220, 201, 26, 151, 188, 103, 107, 8, 229, 181, 145, 208,
+ 235, 215, 201, 25, 208, 196, 132, 31, 29, 164, 9, 140, 72, 115, 218,
+ 175, 176, 154, 16, 15, 116, 10, 92, 145, 21, 115, 91, 59, 97, 199,
+ 60, 188, 80, 125, 43, 195, 24, 211, 81, 23, 185, 81, 73, 66, 248,
+ 158, 14, 59, 21, 58, 127, 126, 155, 28, 123, 48, 138, 28, 237, 91,
+ 39, 214, 75, 187, 75, 36, 235, 90, 132, 65, 109, 137, 249, 15, 227,
+ 158, 120, 8, 107, 208, 173, 204, 15, 96, 177, 179, 141, 122, 51, 94,
+ 231, 249, 54, 19, 218, 164, 220, 238, 23, 20, 163, 190, 110, 165, 219,
+ 145, 21, 132, 137, 206, 230, 94, 77, 157, 197, 38, 223, 194, 216, 27,
+ 165, 157, 181, 150, 127, 31, 149, 78, 145, 242, 17, 250, 178, 184, 245,
+ 253, 68, 148, 123, 102, 110, 200, 177, 40, 152, 245, 250, 70, 220, 171,
+ 11, 219, 219, 239, 18, 24, 171, 171, 60, 26, 130, 66, 217, 242, 217,
+ 59, 61, 86, 138, 248, 212, 63, 175, 222, 215, 12, 197, 49, 119, 213,
+ 58, 226, 23, 109, 221, 199, 174, 197, 217, 174, 105, 179, 100, 29, 239,
+ 213, 194, 138, 84, 131, 94, 83, 63, 118, 90, 232, 144, 48, 245, 123,
+ 234, 82, 148, 182, 174, 248, 40, 135, 35, 211, 64, 223, 152, 152, 244,
+ 190, 227, 139, 183, 46, 74, 196, 172, 235, 196, 214, 142, 241, 77, 3,
+ 41, 141, 121, 167, 208, 199, 150, 155, 79, 43, 115, 180, 27, 144, 176,
+ 63, 103, 150, 75, 111, 23, 149, 193, 42, 190, 58, 223, 240, 45, 83,
+ 77, 171, 41, 196, 194, 120, 151, 96, 183, 187, 59, 220, 61, 36, 217,
+ 196, 35, 57, 49, 186, 1, 200, 184, 146, 82, 71, 206, 135, 53, 218,
+ 122, 230, 235, 171, 76, 227, 114, 124, 35, 152, 98, 151, 250, 102, 124,
+ 206, 111, 164, 39, 223, 118, 179, 25, 29, 252, 50, 210, 51, 18, 170,
+ 214, 214, 42, 191, 156, 247, 153, 187, 101, 228, 128, 145, 95, 204, 194,
+ 207, 176, 128, 238, 70, 163, 231, 104, 5, 251, 139, 161, 30, 71, 199,
+ 26, 15, 238, 210, 119, 60, 24, 244, 86, 208, 87, 155, 165, 97, 214,
+ 160, 26, 234, 244, 5, 76, 45, 99, 162, 120, 138, 251, 214, 233, 253,
+ 25, 215, 10, 145, 178, 234, 50, 210, 185, 175, 69, 135, 74, 132, 80,
+ 233, 142, 173, 79, 245, 77, 102, 21, 51, 145, 32, 94, 123, 250, 66,
+ 131, 122, 187, 71, 173, 175, 58, 11, 235, 70, 147, 122, 158, 85, 188,
+ 63, 207, 74, 102, 182, 152, 38, 255, 195, 113, 2, 109, 102, 219, 59,
+ 36, 229, 239, 159, 4, 68, 115, 109, 125, 114, 188, 99, 195, 181, 83,
+ 224, 193, 247, 88, 10, 5, 187, 206, 240, 173, 250, 76, 199, 226, 13,
+ 149, 236, 108, 43, 84, 151, 252, 214, 9, 127, 65, 237, 183, 60, 221,
+ 3, 137, 23, 47, 182, 148, 91, 37, 132, 61, 10, 30, 69, 116, 165,
+ 247, 54, 187, 171, 174, 48, 38, 168, 157, 91, 53, 140, 141, 37, 169,
+ 63, 129, 89, 16, 106, 115, 120, 128, 149, 111, 95, 211, 112, 68, 156,
+ 169, 189, 80, 104, 212, 45, 16, 209, 104, 249, 124, 80, 124, 239, 11,
+ 175, 209, 88, 145, 127, 61, 164, 23, 129, 200, 252, 126, 201, 228, 20,
+ 66, 13, 62, 29, 30, 90, 83, 123, 167, 238, 56, 139, 31, 153, 118,
+ 125, 145, 82, 67, 103, 16, 149, 248, 99, 147, 111, 197, 73, 183, 82,
+ 193, 61, 43, 173, 123, 177, 87, 42, 80, 167, 208, 4, 8, 36, 24,
+ 60, 28, 135, 90, 44, 44, 172, 181, 145, 231, 40, 221, 231, 102, 69,
+ 199, 176, 239, 14, 47, 53, 100, 159, 123, 199, 210, 238, 230, 175, 202,
+ 123, 162, 52, 85, 115, 191, 99, 231, 206, 68, 110, 167, 43, 178, 151,
+ 196, 114, 126, 254, 201, 155, 240, 185, 4, 71, 63, 250, 53, 209, 107,
+ 137, 155, 18, 3, 62, 111, 180, 16, 103, 5, 76, 18, 118, 174, 63,
+ 175, 117, 187, 230, 161, 64, 156, 99, 255, 14, 233, 206, 226, 129, 209,
+ 246, 190, 255, 76, 82, 91, 212, 123, 163, 150, 59, 138, 219, 219, 205,
+ 155, 232, 199, 85, 123, 201, 41, 227, 155, 175, 62, 189, 38, 153, 64,
+ 154, 91, 27, 208, 233, 119, 170, 101, 245, 205, 33, 35, 134, 228, 142,
+ 223, 9, 175, 88, 93, 165, 231, 159, 148, 52, 170, 165, 121, 125, 178,
+ 30, 111, 23, 60, 144, 117, 29, 219, 141, 185, 222, 139, 97, 149, 165,
+ 131, 83, 233, 35, 126, 45, 225, 121, 86, 212, 54, 177, 139, 35, 62,
+ 151, 213, 98, 123, 11, 30, 199, 155, 48, 189, 199, 78, 9, 198, 77,
+ 98, 47, 207, 116, 33, 217, 67, 167, 178, 194, 150, 243, 111, 239, 154,
+ 155, 255, 246, 225, 233, 135, 134, 172, 226, 16, 181, 152, 150, 39, 14,
+ 109, 46, 183, 93, 22, 38, 116, 245, 253, 25, 248, 55, 73, 189, 77,
+ 173, 6, 18, 242, 252, 181, 6, 198, 242, 34, 252, 44, 164, 137, 138,
+ 247, 179, 124, 106, 178, 232, 197, 66, 98, 104, 194, 219, 88, 152, 219,
+ 40, 167, 105, 38, 220, 135, 89, 180, 45, 219, 103, 106, 131, 5, 48,
+ 61, 30, 119, 62, 46, 49, 24, 215, 204, 233, 204, 162, 172, 55, 60,
+ 210, 154, 101, 16, 136, 187, 118, 61, 185, 225, 19, 186, 159, 164, 189,
+ 210, 78, 183, 98, 94, 92, 249, 34, 9, 93, 169, 67, 6, 122, 97,
+ 172, 227, 19, 158, 114, 206, 76, 151, 151, 119, 237, 140, 52, 40, 21,
+ 252, 66, 194, 90, 231, 190, 192, 136, 77, 163, 155, 33, 4, 95, 212,
+ 82, 56, 148, 251, 250, 176, 23, 125, 84, 249, 35, 135, 137, 158, 214,
+ 167, 176, 58, 131, 38, 225, 252, 252, 43, 172, 97, 149, 151, 206, 51,
+ 49, 81, 51, 140, 4, 133, 221, 245, 172, 17, 49, 20, 78, 142, 236,
+ 110, 24, 101, 125, 249, 149, 224, 157, 124, 234, 40, 171, 153, 14, 167,
+ 222, 107, 138, 43, 155, 42, 2, 138, 53, 149, 230, 217, 154, 68, 108,
+ 86, 46, 166, 35, 3, 169, 73, 61, 39, 38, 90, 62, 31, 51, 243,
+ 26, 30, 158, 220, 108, 46, 85, 19, 10, 140, 126, 240, 13, 79, 93,
+ 184, 56, 237, 209, 163, 143, 82, 250, 47, 91, 115, 164, 166, 195, 222,
+ 250, 112, 187, 88, 58, 126, 27, 122, 221, 109, 136, 113, 205, 155, 228,
+ 146, 104, 247, 220, 43, 225, 186, 88, 246, 148, 151, 184, 16, 123, 112,
+ 216, 51, 159, 228, 227, 247, 171, 131, 250, 67, 163, 220, 251, 10, 131,
+ 216, 232, 171, 183, 155, 138, 125, 46, 83, 169, 62, 100, 136, 98, 43,
+ 109, 127, 77, 20, 126, 245, 196, 196, 227, 20, 10, 184, 38, 91, 248,
+ 176, 245, 235, 45, 241, 20, 202, 235, 94, 201, 241, 241, 251, 195, 82,
+ 82, 142, 55, 87, 38, 239, 18, 51, 20, 46, 4, 229, 40, 58, 30,
+ 14, 223, 98, 204, 201, 98, 11, 176, 22, 38, 158, 188, 131, 58, 80,
+ 109, 211, 155, 135, 16, 157, 193, 60, 103, 127, 249, 133, 160, 70, 223,
+ 202, 163, 81, 86, 230, 103, 106, 159, 215, 247, 69, 116, 46, 223, 204,
+ 109, 226, 36, 189, 41, 100, 123, 237, 164, 179, 132, 144, 69, 223, 151,
+ 232, 203, 48, 46, 214, 1, 197, 41, 148, 126, 88, 102, 153, 140, 140,
+ 231, 223, 76, 139, 235, 65, 217, 161, 67, 20, 253, 177, 191, 205, 52,
+ 81, 70, 3, 175, 53, 107, 136, 11, 65, 158, 86, 48, 244, 157, 42,
+ 222, 98, 79, 206, 171, 14, 114, 86, 35, 195, 98, 212, 43, 114, 209,
+ 175, 196, 21, 158, 223, 115, 38, 230, 77, 201, 37, 77, 185, 151, 194,
+ 58, 100, 200, 77, 211, 164, 172, 193, 17, 194, 106, 114, 67, 39, 250,
+ 68, 85, 20, 67, 150, 202, 58, 166, 43, 107, 239, 154, 131, 187, 117,
+ 182, 215, 170, 42, 181, 103, 57, 139, 152, 152, 112, 110, 192, 124, 26,
+ 245, 107, 98, 55, 20, 105, 94, 91, 154, 254, 119, 108, 149, 158, 37,
+ 168, 175, 10, 50, 218, 211, 217, 35, 154, 91, 66, 238, 190, 230, 76,
+ 167, 226, 120, 85, 238, 44, 83, 114, 223, 178, 110, 119, 72, 48, 97,
+ 126, 49, 171, 113, 48, 179, 41, 209, 222, 212, 178, 78, 61, 175, 57,
+ 210, 129, 53, 238, 98, 178, 122, 134, 136, 213, 13, 95, 65, 29, 110,
+ 185, 50, 8, 10, 232, 53, 209, 242, 40, 65, 107, 186, 175, 24, 250,
+ 144, 223, 233, 170, 35, 193, 210, 142, 250, 88, 22, 27, 82, 60, 157,
+ 180, 241, 140, 115, 118, 116, 225, 23, 132, 83, 200, 115, 37, 22, 77,
+ 86, 37, 195, 154, 175, 78, 31, 242, 15, 123, 231, 106, 180, 28, 38,
+ 234, 59, 118, 89, 210, 152, 224, 75, 145, 12, 27, 26, 63, 155, 176,
+ 203, 149, 56, 93, 255, 161, 181, 83, 136, 64, 189, 25, 207, 84, 68,
+ 255, 62, 255, 41, 116, 251, 42, 217, 144, 146, 135, 65, 100, 65, 219,
+ 164, 190, 139, 170, 178, 202, 106, 117, 170, 63, 25, 241, 203, 15, 10,
+ 215, 9, 58, 6, 117, 60, 189, 170, 104, 92, 60, 136, 23, 165, 212,
+ 23, 243, 103, 197, 161, 237, 26, 239, 41, 156, 12, 137, 211, 30, 183,
+ 147, 43, 165, 105, 88, 248, 251, 190, 170, 31, 234, 149, 207, 237, 90,
+ 153, 198, 147, 156, 191, 77, 134, 79, 211, 132, 254, 241, 129, 135, 203,
+ 162, 90, 239, 186, 186, 236, 62, 91, 235, 142, 17, 11, 154, 138, 225,
+ 228, 157, 46, 79, 137, 126, 61, 235, 160, 168, 80, 35, 45, 122, 195,
+ 90, 117, 106, 221, 146, 219, 147, 239, 61, 84, 155, 72, 163, 186, 230,
+ 144, 198, 243, 217, 15, 90, 204, 239, 101, 189, 72, 55, 66, 151, 151,
+ 106, 70, 160, 153, 29, 206, 226, 167, 228, 210, 75, 189, 18, 131, 228,
+ 34, 220, 182, 177, 250, 204, 49, 195, 191, 50, 236, 93, 238, 178, 207,
+ 84, 47, 141, 160, 88, 242, 251, 137, 88, 68, 196, 132, 147, 46, 207,
+ 238, 190, 81, 242, 146, 203, 200, 77, 120, 197, 157, 99, 29, 199, 138,
+ 37, 174, 235, 108, 133, 68, 40, 173, 167, 208, 240, 41, 52, 103, 67,
+ 180, 61, 189, 47, 66, 143, 126, 179, 142, 136, 222, 208, 211, 199, 237,
+ 218, 61, 204, 118, 158, 64, 35, 132, 56, 66, 193, 175, 223, 202, 138,
+ 114, 42, 199, 102, 80, 57, 208, 67, 168, 216, 240, 79, 76, 239, 118,
+ 170, 125, 93, 193, 115, 48, 145, 75, 219, 247, 195, 204, 43, 12, 209,
+ 96, 238, 88, 190, 171, 158, 105, 118, 10, 241, 174, 21, 104, 16, 170,
+ 11, 197, 80, 95, 127, 146, 207, 201, 179, 20, 134, 105, 227, 248, 158,
+ 224, 125, 104, 168, 189, 214, 10, 54, 115, 182, 6, 239, 128, 165, 218,
+ 114, 29, 97, 120, 83, 189, 161, 71, 182, 23, 106, 126, 96, 123, 167,
+ 108, 59, 196, 81, 56, 255, 117, 84, 235, 107, 89, 18, 49, 191, 150,
+ 62, 59, 110, 0, 29, 132, 248, 46, 183, 195, 251, 194, 18, 211, 35,
+ 43, 70, 87, 58, 199, 192, 40, 46, 201, 113, 164, 116, 124, 132, 40,
+ 84, 193, 248, 248, 135, 226, 172, 153, 175, 207, 149, 65, 92, 133, 24,
+ 148, 87, 93, 150, 230, 175, 228, 233, 112, 65, 31, 203, 137, 197, 180,
+ 49, 31, 233, 144, 92, 144, 190, 72, 250, 84, 212, 123, 146, 115, 66,
+ 85, 147, 255, 72, 224, 118, 227, 179, 46, 97, 225, 128, 34, 57, 204,
+ 171, 136, 242, 177, 104, 131, 123, 206, 88, 35, 185, 55, 18, 4, 179,
+ 81, 88, 139, 229, 69, 223, 58, 99, 185, 225, 95, 112, 100, 180, 226,
+ 140, 192, 72, 86, 241, 33, 146, 51, 84, 184, 248, 234, 234, 144, 71,
+ 248, 126, 253, 81, 153, 198, 124, 175, 237, 122, 206, 53, 118, 207, 4,
+ 217, 201, 148, 231, 174, 243, 45, 52, 76, 213, 21, 237, 179, 100, 87,
+ 142, 82, 80, 75, 229, 94, 40, 47, 244, 87, 157, 48, 61, 194, 33,
+ 65, 24, 187, 245, 164, 88, 179, 47, 231, 106, 164, 228, 81, 89, 50,
+ 83, 188, 42, 223, 108, 23, 79, 138, 137, 31, 3, 29, 59, 233, 144,
+ 68, 220, 187, 172, 221, 243, 158, 239, 13, 52, 241, 181, 84, 63, 135,
+ 166, 74, 123, 22, 22, 58, 171, 153, 222, 153, 122, 43, 169, 42, 152,
+ 216, 217, 54, 215, 213, 53, 63, 223, 195, 234, 197, 106, 50, 100, 92,
+ 148, 35, 93, 234, 129, 142, 137, 183, 208, 75, 153, 119, 244, 118, 105,
+ 76, 236, 209, 165, 88, 42, 219, 151, 146, 34, 232, 162, 181, 211, 141,
+ 138, 119, 134, 132, 42, 179, 232, 162, 155, 19, 207, 213, 233, 214, 47,
+ 40, 162, 61, 205, 233, 29, 189, 86, 42, 118, 173, 125, 216, 50, 171,
+ 83, 137, 132, 51, 240, 206, 84, 13, 154, 163, 113, 153, 186, 183, 74,
+ 105, 145, 95, 19, 47, 225, 251, 27, 158, 185, 76, 57, 55, 213, 165,
+ 234, 102, 138, 16, 212, 95, 84, 125, 222, 62, 164, 208, 200, 61, 167,
+ 233, 45, 43, 67, 172, 33, 80, 212, 84, 127, 194, 119, 77, 89, 123,
+ 191, 164, 214, 138, 143, 101, 228, 51, 153, 138, 183, 126, 42, 229, 170,
+ 249, 183, 4, 85, 92, 51, 61, 36, 226, 114, 235, 227, 202, 54, 44,
+ 114, 178, 119, 23, 132, 31, 68, 11, 17, 122, 196, 168, 190, 170, 247,
+ 15, 52, 189, 197, 26, 63, 166, 209, 80, 158, 79, 67, 127, 10, 17,
+ 93, 83, 79, 81, 229, 46, 120, 112, 205, 224, 218, 75, 105, 126, 6,
+ 147, 112, 246, 5, 181, 190, 21, 237, 129, 188, 140, 72, 77, 62, 236,
+ 168, 214, 215, 91, 88, 59, 70, 39, 67, 254, 187, 85, 106, 19, 163,
+ 58, 99, 217, 225, 252, 35, 164, 115, 149, 162, 230, 118, 60, 31, 179,
+ 249, 158, 84, 40, 222, 108, 43, 12, 201, 136, 126, 169, 144, 175, 231,
+ 190, 125, 20, 154, 40, 97, 111, 201, 55, 52, 217, 128, 197, 186, 54,
+ 78, 110, 251, 208, 144, 50, 248, 72, 53, 162, 99, 161, 103, 32, 77,
+ 222, 70, 141, 56, 151, 133, 140, 152, 0, 225, 136, 45, 159, 173, 246,
+ 88, 76, 21, 51, 171, 111, 30, 71, 190, 45, 181, 220, 214, 152, 50,
+ 206, 46, 202, 102, 60, 155, 234, 110, 209, 90, 148, 141, 47, 215, 117,
+ 73, 25, 11, 13, 2, 230, 36, 229, 169, 22, 233, 55, 175, 210, 228,
+ 49, 155, 83, 62, 52, 188, 186, 82, 193, 156, 144, 165, 172, 81, 84,
+ 115, 121, 188, 243, 19, 251, 62, 41, 147, 34, 90, 38, 243, 203, 7,
+ 46, 150, 44, 147, 117, 62, 15, 229, 167, 231, 44, 74, 242, 3, 188,
+ 55, 54, 183, 187, 109, 137, 205, 59, 178, 159, 217, 87, 19, 197, 161,
+ 222, 192, 46, 145, 126, 29, 212, 105, 248, 74, 242, 144, 140, 198, 142,
+ 101, 101, 230, 162, 101, 195, 156, 38, 86, 135, 184, 250, 56, 7, 57,
+ 173, 0, 187, 147, 129, 43, 67, 14, 98, 10, 198, 220, 80, 64, 122,
+ 186, 226, 68, 41, 170, 67, 181, 232, 67, 22, 104, 130, 224, 155, 43,
+ 187, 197, 209, 13, 97, 143, 71, 81, 8, 177, 87, 16, 13, 41, 214,
+ 118, 203, 162, 214, 91, 37, 43, 146, 67, 7, 234, 20, 93, 144, 154,
+ 177, 56, 89, 7, 166, 110, 160, 157, 246, 62, 91, 194, 125, 223, 151,
+ 89, 35, 199, 209, 216, 169, 252, 205, 165, 250, 64, 142, 115, 28, 187,
+ 55, 234, 9, 73, 121, 35, 19, 115, 199, 158, 115, 197, 43, 54, 87,
+ 85, 218, 81, 83, 123, 1, 86, 202, 28, 10, 157, 154, 34, 3, 133,
+ 224, 102, 254, 9, 251, 164, 111, 75, 89, 130, 236, 183, 76, 67, 159,
+ 133, 220, 93, 223, 78, 50, 157, 148, 231, 153, 199, 240, 235, 14, 9,
+ 17, 227, 66, 203, 214, 94, 120, 170, 16, 95, 25, 61, 113, 53, 41,
+ 34, 91, 107, 111, 234, 33, 250, 4, 233, 18, 37, 197, 116, 74, 103,
+ 37, 65, 223, 219, 56, 254, 27, 47, 220, 103, 153, 55, 79, 161, 9,
+ 61, 86, 61, 222, 97, 125, 89, 232, 107, 59, 179, 60, 173, 93, 152,
+ 191, 231, 222, 80, 173, 229, 160, 118, 243, 155, 160, 143, 6, 201, 132,
+ 252, 29, 27, 28, 143, 15, 130, 12, 217, 155, 209, 120, 66, 125, 177,
+ 10, 91, 250, 215, 123, 140, 221, 144, 179, 251, 66, 241, 154, 87, 12,
+ 66, 38, 184, 69, 179, 166, 212, 7, 89, 161, 35, 155, 78, 204, 79,
+ 87, 227, 45, 226, 155, 14, 93, 251, 101, 203, 205, 154, 199, 81, 173,
+ 12, 183, 36, 233, 25, 169, 68, 11, 247, 179, 83, 88, 125, 21, 42,
+ 87, 200, 222, 49, 155, 222, 149, 27, 207, 117, 198, 115, 93, 73, 103,
+ 224, 97, 120, 76, 28, 12, 37, 143, 175, 217, 134, 89, 176, 75, 77,
+ 16, 171, 4, 163, 183, 197, 61, 42, 248, 58, 183, 60, 164, 97, 57,
+ 207, 195, 241, 117, 61, 165, 131, 170, 61, 169, 224, 46, 39, 71, 89,
+ 181, 1, 218, 147, 173, 10, 52, 155, 224, 112, 33, 243, 192, 168, 243,
+ 105, 21, 87, 241, 69, 241, 50, 93, 216, 209, 229, 102, 47, 232, 236,
+ 222, 115, 49, 161, 176, 118, 157, 77, 253, 146, 252, 218, 220, 181, 77,
+ 69, 218, 40, 138, 96, 151, 168, 101, 207, 25, 161, 236, 99, 48, 243,
+ 146, 3, 15, 170, 226, 50, 245, 26, 187, 75, 165, 122, 29, 126, 106,
+ 163, 252, 71, 234, 160, 237, 149, 225, 88, 108, 4, 63, 17, 2, 49,
+ 134, 253, 97, 27, 230, 201, 17, 85, 129, 214, 208, 79, 161, 182, 1,
+ 213, 108, 50, 46, 56, 231, 8, 108, 172, 151, 178, 141, 40, 177, 115,
+ 162, 88, 35, 23, 114, 187, 191, 241, 226, 237, 243, 14, 12, 22, 115,
+ 19, 147, 24, 231, 36, 167, 110, 177, 71, 173, 12, 246, 156, 111, 83,
+ 200, 40, 188, 157, 0, 51, 16, 45, 205, 40, 225, 46, 149, 146, 90,
+ 101, 11, 23, 171, 59, 237, 151, 219, 225, 223, 90, 158, 110, 83, 210,
+ 11, 79, 174, 126, 107, 53, 37, 25, 72, 150, 225, 214, 203, 146, 136,
+ 123, 53, 37, 18, 25, 158, 38, 73, 38, 197, 226, 234, 25, 241, 200,
+ 225, 72, 233, 249, 78, 253, 88, 54, 113, 130, 28, 46, 98, 155, 158,
+ 175, 197, 92, 138, 217, 68, 134, 105, 199, 156, 118, 242, 156, 90, 82,
+ 236, 117, 194, 23, 105, 135, 99, 8, 123, 116, 89, 149, 31, 39, 181,
+ 135, 111, 66, 180, 175, 57, 21, 135, 174, 123, 219, 165, 223, 232, 243,
+ 175, 155, 199, 229, 151, 109, 38, 46, 163, 245, 201, 166, 246, 98, 157,
+ 204, 36, 25, 117, 49, 167, 113, 193, 245, 141, 138, 98, 142, 254, 82,
+ 206, 113, 185, 59, 131, 106, 235, 146, 231, 70, 218, 96, 31, 202, 103,
+ 1, 50, 68, 113, 180, 100, 225, 181, 15, 29, 41, 220, 143, 70, 57,
+ 49, 89, 88, 48, 115, 141, 253, 194, 162, 250, 230, 122, 54, 171, 40,
+ 124, 90, 24, 89, 50, 237, 71, 10, 244, 42, 173, 71, 79, 212, 118,
+ 215, 94, 239, 105, 112, 144, 96, 169, 226, 47, 50, 109, 106, 52, 99,
+ 30, 249, 172, 112, 20, 219, 85, 98, 77, 241, 92, 233, 34, 225, 28,
+ 163, 15, 42, 125, 91, 133, 131, 59, 93, 241, 106, 125, 148, 104, 150,
+ 141, 68, 220, 242, 201, 186, 52, 94, 148, 77, 254, 186, 229, 128, 216,
+ 149, 175, 170, 132, 157, 184, 38, 50, 235, 242, 171, 215, 61, 75, 112,
+ 39, 52, 149, 219, 110, 60, 126, 106, 73, 29, 109, 12, 189, 189, 19,
+ 211, 146, 45, 195, 91, 45, 100, 25, 156, 89, 110, 207, 28, 157, 190,
+ 252, 190, 166, 108, 137, 162, 116, 112, 9, 59, 235, 115, 250, 22, 109,
+ 179, 100, 184, 218, 225, 129, 246, 138, 244, 235, 98, 254, 121, 131, 209,
+ 33, 166, 152, 142, 176, 231, 66, 171, 59, 43, 173, 131, 148, 15, 163,
+ 89, 237, 51, 77, 12, 37, 111, 159, 66, 3, 135, 30, 59, 6, 146,
+ 247, 237, 158, 222, 123, 170, 144, 56, 65, 230, 121, 172, 119, 71, 15,
+ 229, 158, 122, 177, 137, 137, 190, 101, 108, 26, 19, 142, 126, 139, 234,
+ 78, 222, 139, 226, 114, 138, 39, 183, 30, 83, 14, 83, 5, 31, 196,
+ 111, 113, 248, 141, 23, 229, 208, 9, 205, 246, 222, 101, 107, 247, 90,
+ 227, 147, 84, 91, 155, 145, 145, 147, 151, 31, 145, 253, 186, 125, 77,
+ 237, 50, 203, 72, 125, 107, 177, 29, 143, 91, 243, 251, 164, 59, 125,
+ 67, 16, 177, 248, 245, 61, 134, 53, 90, 15, 159, 175, 61, 195, 12,
+ 170, 40, 154, 134, 250, 248, 23, 240, 82, 191, 124, 26, 24, 126, 244,
+ 88, 170, 149, 176, 79, 35, 92, 200, 147, 23, 177, 48, 219, 107, 34,
+ 24, 147, 219, 93, 100, 3, 59, 55, 237, 112, 101, 62, 34, 129, 250,
+ 60, 163, 72, 20, 77, 92, 220, 241, 164, 176, 101, 99, 113, 38, 13,
+ 165, 146, 212, 253, 226, 126, 195, 227, 83, 136, 223, 119, 166, 244, 190,
+ 131, 214, 34, 253, 83, 95, 100, 150, 209, 198, 107, 62, 167, 125, 59,
+ 98, 73, 28, 235, 100, 6, 61, 77, 132, 2, 118, 26, 235, 203, 239,
+ 22, 43, 179, 75, 110, 236, 146, 87, 115, 189, 122, 213, 116, 213, 167,
+ 255, 142, 206, 65, 196, 14, 147, 222, 192, 90, 133, 214, 41, 84, 229,
+ 124, 238, 248, 238, 65, 252, 240, 69, 10, 124, 239, 196, 150, 187, 43,
+ 136, 147, 74, 220, 226, 104, 142, 232, 7, 86, 93, 174, 73, 249, 171,
+ 62, 131, 62, 89, 229, 70, 7, 102, 151, 47, 178, 105, 62, 87, 189,
+ 200, 253, 172, 124, 119, 149, 116, 114, 202, 85, 172, 127, 168, 211, 91,
+ 155, 242, 117, 38, 15, 207, 237, 199, 230, 111, 197, 139, 15, 52, 238,
+ 83, 245, 22, 126, 59, 234, 160, 214, 218, 60, 204, 205, 87, 125, 200,
+ 158, 33, 73, 136, 182, 22, 48, 151, 159, 232, 29, 113, 80, 177, 94,
+ 237, 121, 239, 81, 29, 238, 219, 88, 206, 33, 239, 170, 221, 83, 40,
+ 205, 45, 109, 144, 220, 248, 170, 180, 141, 56, 78, 138, 231, 88, 36,
+ 54, 61, 126, 181, 251, 215, 100, 149, 85, 164, 234, 92, 99, 226, 17,
+ 127, 19, 228, 175, 21, 201, 205, 45, 147, 185, 213, 118, 190, 72, 216,
+ 229, 211, 187, 47, 16, 93, 194, 166, 182, 198, 228, 5, 47, 113, 199,
+ 33, 197, 189, 242, 98, 127, 133, 248, 255, 152, 251, 238, 176, 40, 146,
+ 231, 239, 37, 232, 154, 80, 84, 84, 48, 174, 1, 19, 138, 128, 98,
+ 32, 237, 204, 168, 96, 150, 83, 48, 7, 64, 5, 5, 84, 196, 128,
+ 9, 88, 64, 49, 11, 102, 209, 83, 49, 220, 137, 152, 0, 81, 81,
+ 1, 215, 156, 191, 162, 39, 138, 98, 88, 3, 6, 76, 152, 21, 65,
+ 223, 238, 221, 233, 158, 94, 220, 157, 89, 126, 187, 127, 188, 247, 60,
+ 60, 214, 51, 215, 93, 53, 85, 83, 159, 234, 234, 234, 176, 113, 35,
+ 67, 19, 70, 165, 218, 205, 142, 29, 51, 197, 219, 37, 175, 243, 145,
+ 159, 206, 117, 18, 223, 158, 30, 80, 100, 57, 119, 195, 187, 215, 255,
+ 203, 161, 172, 39, 55, 95, 21, 189, 103, 146, 181, 229, 116, 235, 224,
+ 135, 91, 2, 191, 126, 45, 233, 89, 245, 162, 185, 137, 200, 201, 225,
+ 238, 144, 26, 131, 142, 44, 189, 111, 107, 148, 119, 201, 216, 178, 87,
+ 199, 196, 225, 115, 99, 199, 31, 233, 179, 34, 113, 246, 119, 143, 135,
+ 57, 235, 139, 47, 250, 118, 61, 126, 254, 194, 196, 230, 59, 30, 133,
+ 22, 30, 29, 181, 125, 244, 198, 143, 149, 90, 53, 61, 155, 122, 193,
+ 190, 126, 179, 216, 2, 81, 181, 143, 103, 87, 181, 152, 178, 170, 164,
+ 243, 207, 123, 99, 51, 82, 141, 211, 182, 7, 230, 173, 27, 239, 58,
+ 204, 126, 73, 233, 181, 254, 71, 110, 31, 113, 244, 237, 221, 181, 123,
+ 69, 241, 223, 115, 215, 93, 157, 241, 106, 222, 152, 127, 246, 7, 15,
+ 178, 171, 243, 171, 166, 131, 217, 178, 231, 73, 11, 63, 29, 28, 179,
+ 244, 221, 189, 83, 227, 118, 25, 175, 111, 183, 160, 66, 134, 85, 201,
+ 128, 3, 127, 167, 219, 126, 60, 79, 221, 217, 153, 94, 241, 174, 40,
+ 62, 241, 75, 199, 14, 31, 31, 53, 252, 52, 186, 167, 197, 215, 47,
+ 247, 191, 110, 62, 183, 68, 210, 252, 68, 45, 75, 247, 177, 77, 14,
+ 127, 186, 21, 102, 118, 207, 161, 228, 192, 141, 139, 238, 61, 103, 13,
+ 47, 248, 222, 42, 255, 89, 78, 199, 177, 33, 237, 251, 92, 91, 252,
+ 168, 121, 219, 109, 177, 215, 210, 236, 175, 70, 134, 13, 237, 153, 212,
+ 226, 201, 104, 233, 18, 183, 224, 106, 51, 182, 57, 77, 180, 152, 254,
+ 245, 164, 245, 127, 87, 235, 90, 198, 250, 68, 141, 171, 242, 213, 170,
+ 96, 253, 191, 233, 71, 110, 251, 31, 168, 231, 22, 116, 179, 111, 219,
+ 38, 143, 191, 85, 254, 246, 185, 94, 106, 112, 187, 138, 19, 36, 11,
+ 219, 103, 63, 62, 58, 98, 236, 251, 185, 159, 179, 18, 70, 36, 95,
+ 9, 170, 56, 136, 154, 254, 172, 249, 138, 33, 231, 55, 190, 51, 22,
+ 251, 55, 24, 113, 177, 210, 160, 251, 7, 188, 158, 2, 135, 27, 176,
+ 62, 173, 112, 89, 199, 134, 9, 251, 6, 157, 55, 50, 218, 88, 227,
+ 202, 10, 227, 176, 176, 195, 137, 105, 59, 175, 29, 201, 77, 144, 90,
+ 53, 60, 246, 211, 251, 112, 220, 111, 145, 107, 131, 12, 159, 110, 222,
+ 15, 221, 159, 45, 156, 88, 146, 59, 249, 248, 225, 136, 95, 183, 140,
+ 250, 116, 107, 86, 121, 208, 253, 129, 197, 67, 130, 44, 190, 73, 242,
+ 220, 123, 76, 49, 202, 143, 75, 121, 233, 186, 219, 247, 254, 250, 103,
+ 251, 237, 51, 101, 231, 250, 61, 245, 17, 31, 152, 249, 207, 192, 185,
+ 14, 97, 19, 108, 247, 153, 45, 221, 213, 123, 230, 39, 144, 43, 22,
+ 188, 190, 254, 43, 126, 244, 222, 144, 246, 50, 241, 215, 157, 91, 151,
+ 135, 31, 127, 248, 79, 221, 228, 235, 23, 189, 178, 69, 39, 118, 27,
+ 53, 79, 254, 247, 99, 199, 46, 67, 162, 115, 91, 77, 113, 107, 209,
+ 54, 244, 88, 239, 61, 23, 237, 107, 255, 22, 93, 233, 82, 103, 198,
+ 207, 226, 137, 109, 119, 30, 13, 54, 105, 91, 225, 249, 189, 136, 46,
+ 174, 21, 66, 63, 118, 56, 234, 217, 126, 104, 207, 161, 162, 208, 164,
+ 116, 179, 95, 185, 19, 166, 78, 89, 254, 210, 234, 181, 227, 17, 185,
+ 81, 252, 253, 58, 226, 205, 142, 78, 85, 75, 230, 216, 5, 180, 147,
+ 248, 78, 52, 31, 226, 33, 174, 159, 252, 32, 48, 197, 163, 185, 53,
+ 211, 62, 41, 170, 69, 13, 167, 35, 7, 19, 90, 247, 154, 48, 249,
+ 242, 237, 6, 33, 30, 75, 239, 254, 106, 63, 212, 255, 192, 17, 73,
+ 146, 115, 74, 69, 170, 249, 164, 15, 55, 234, 140, 12, 158, 177, 111,
+ 167, 127, 152, 168, 203, 210, 109, 93, 204, 198, 220, 14, 54, 86, 88,
+ 69, 85, 205, 156, 250, 229, 74, 164, 237, 62, 115, 167, 153, 235, 124,
+ 2, 166, 26, 187, 102, 175, 168, 154, 145, 150, 50, 242, 185, 233, 39,
+ 209, 89, 143, 154, 63, 102, 213, 240, 151, 213, 152, 236, 107, 69, 15,
+ 202, 253, 104, 101, 53, 65, 122, 213, 251, 115, 225, 210, 49, 233, 51,
+ 18, 218, 54, 59, 246, 120, 85, 97, 247, 183, 159, 3, 246, 30, 111,
+ 223, 243, 129, 200, 104, 243, 182, 90, 190, 81, 86, 93, 76, 214, 143,
+ 48, 59, 176, 108, 244, 178, 9, 11, 170, 255, 21, 20, 93, 213, 207,
+ 105, 78, 150, 219, 232, 58, 191, 255, 251, 186, 237, 192, 223, 206, 99,
+ 198, 190, 185, 179, 160, 212, 239, 200, 187, 133, 23, 23, 172, 78, 79,
+ 105, 240, 97, 90, 238, 193, 153, 165, 238, 167, 38, 254, 37, 95, 115,
+ 176, 222, 253, 23, 67, 67, 218, 123, 189, 202, 123, 43, 61, 62, 46,
+ 119, 199, 133, 255, 253, 22, 245, 46, 157, 250, 101, 108, 206, 188, 205,
+ 83, 74, 157, 158, 230, 63, 240, 115, 28, 98, 41, 94, 91, 250, 86,
+ 114, 245, 127, 231, 54, 174, 247, 119, 232, 253, 164, 247, 157, 163, 165,
+ 131, 139, 251, 28, 248, 177, 249, 216, 219, 110, 173, 102, 153, 156, 185,
+ 176, 155, 41, 237, 82, 220, 252, 240, 181, 177, 153, 25, 25, 13, 54,
+ 201, 47, 252, 188, 151, 48, 182, 239, 247, 26, 159, 79, 6, 205, 12,
+ 95, 115, 95, 145, 60, 252, 180, 251, 249, 1, 143, 30, 223, 57, 244,
+ 198, 121, 209, 190, 143, 43, 171, 116, 235, 186, 216, 109, 194, 183, 73,
+ 179, 222, 122, 205, 247, 30, 180, 176, 237, 190, 184, 21, 205, 101, 206,
+ 29, 155, 12, 57, 124, 98, 202, 197, 228, 54, 109, 45, 19, 86, 201,
+ 229, 185, 125, 38, 79, 238, 92, 115, 228, 129, 23, 139, 31, 55, 46,
+ 248, 22, 100, 147, 81, 119, 229, 179, 117, 70, 55, 98, 140, 79, 14,
+ 251, 228, 113, 176, 81, 224, 230, 191, 108, 22, 110, 237, 255, 107, 87,
+ 163, 113, 97, 245, 110, 79, 54, 206, 153, 118, 101, 75, 212, 226, 22,
+ 126, 251, 199, 30, 165, 26, 15, 253, 126, 191, 90, 218, 166, 143, 146,
+ 233, 230, 161, 151, 238, 92, 190, 178, 123, 111, 231, 170, 54, 201, 41,
+ 213, 29, 106, 93, 221, 213, 205, 56, 194, 166, 203, 149, 53, 195, 95,
+ 79, 27, 26, 252, 163, 206, 146, 118, 87, 187, 84, 180, 31, 60, 178,
+ 195, 158, 116, 47, 219, 142, 65, 255, 60, 48, 126, 49, 186, 239, 181,
+ 163, 91, 15, 37, 222, 170, 247, 63, 171, 166, 67, 234, 214, 105, 97,
+ 118, 168, 153, 91, 197, 177, 238, 137, 142, 63, 115, 7, 181, 15, 121,
+ 28, 124, 41, 202, 230, 237, 249, 57, 119, 122, 47, 191, 20, 208, 240,
+ 201, 121, 102, 152, 108, 215, 30, 151, 131, 191, 190, 238, 155, 119, 46,
+ 112, 197, 194, 117, 49, 157, 198, 215, 117, 168, 226, 97, 47, 77, 240,
+ 222, 248, 210, 114, 100, 207, 37, 115, 143, 154, 22, 100, 36, 216, 12,
+ 31, 124, 241, 214, 139, 119, 245, 235, 52, 207, 184, 240, 91, 244, 229,
+ 118, 114, 114, 179, 27, 99, 74, 71, 215, 107, 219, 106, 224, 163, 254,
+ 195, 45, 86, 223, 57, 244, 98, 76, 11, 73, 179, 126, 86, 62, 237,
+ 198, 158, 184, 113, 224, 192, 229, 148, 186, 93, 172, 197, 69, 65, 147,
+ 206, 173, 93, 99, 243, 177, 85, 66, 104, 142, 247, 144, 228, 81, 7,
+ 76, 21, 153, 133, 137, 230, 103, 246, 76, 25, 253, 35, 43, 47, 112,
+ 253, 224, 251, 213, 115, 134, 231, 255, 19, 102, 118, 105, 112, 147, 197,
+ 219, 66, 186, 188, 176, 61, 56, 105, 95, 244, 209, 74, 145, 107, 26,
+ 100, 138, 46, 77, 99, 150, 103, 143, 238, 62, 180, 191, 119, 179, 79,
+ 237, 101, 91, 110, 93, 169, 59, 113, 204, 192, 209, 163, 50, 239, 85,
+ 183, 185, 191, 59, 96, 68, 45, 247, 144, 210, 172, 213, 14, 214, 3,
+ 250, 123, 231, 23, 207, 152, 59, 198, 42, 122, 253, 149, 140, 67, 85,
+ 46, 159, 186, 63, 61, 45, 255, 104, 65, 224, 250, 252, 209, 113, 25,
+ 87, 163, 29, 188, 31, 122, 46, 15, 30, 21, 185, 113, 229, 241, 245,
+ 255, 182, 47, 169, 215, 44, 165, 170, 109, 43, 255, 154, 63, 42, 214,
+ 120, 49, 225, 85, 78, 216, 180, 251, 237, 111, 119, 158, 228, 179, 125,
+ 84, 71, 55, 83, 217, 151, 143, 37, 254, 78, 171, 54, 108, 235, 227,
+ 216, 55, 108, 242, 196, 197, 97, 145, 171, 79, 53, 172, 244, 50, 240,
+ 195, 235, 253, 159, 223, 30, 92, 87, 55, 224, 127, 135, 23, 90, 153,
+ 84, 219, 245, 121, 239, 145, 187, 145, 97, 116, 226, 16, 102, 135, 241,
+ 85, 163, 17, 185, 10, 139, 143, 201, 247, 183, 72, 27, 143, 168, 209,
+ 173, 120, 93, 255, 248, 148, 214, 109, 75, 158, 119, 165, 62, 207, 219,
+ 48, 252, 82, 241, 244, 172, 141, 79, 227, 167, 52, 207, 119, 153, 89,
+ 24, 231, 151, 99, 124, 251, 203, 237, 85, 178, 37, 207, 127, 5, 252,
+ 156, 101, 155, 36, 237, 191, 99, 245, 237, 213, 67, 171, 13, 91, 119,
+ 223, 120, 224, 122, 151, 77, 149, 74, 27, 28, 177, 56, 158, 109, 223,
+ 182, 202, 182, 54, 91, 214, 109, 27, 249, 57, 122, 210, 210, 211, 107,
+ 198, 62, 150, 249, 181, 152, 90, 122, 254, 102, 233, 22, 139, 110, 126,
+ 219, 22, 47, 232, 190, 112, 157, 255, 149, 153, 19, 221, 182, 184, 246,
+ 57, 208, 115, 216, 162, 102, 86, 244, 167, 211, 103, 247, 228, 116, 31,
+ 178, 50, 90, 30, 229, 77, 109, 75, 138, 52, 118, 201, 11, 218, 145,
+ 217, 127, 218, 194, 171, 227, 23, 219, 121, 236, 169, 244, 241, 229, 75,
+ 155, 216, 42, 227, 147, 63, 136, 253, 7, 57, 121, 108, 104, 95, 101,
+ 85, 248, 192, 69, 173, 173, 199, 117, 116, 158, 253, 52, 209, 225, 86,
+ 90, 119, 247, 1, 70, 62, 93, 187, 236, 217, 251, 185, 208, 115, 129,
+ 104, 251, 67, 202, 37, 172, 241, 132, 152, 189, 161, 149, 37, 117, 242,
+ 122, 21, 13, 185, 181, 58, 130, 170, 120, 185, 197, 165, 70, 45, 222,
+ 39, 110, 166, 170, 13, 167, 68, 173, 29, 170, 63, 139, 236, 192, 28,
+ 173, 213, 194, 188, 206, 242, 97, 149, 86, 91, 172, 140, 59, 177, 126,
+ 201, 125, 219, 225, 141, 107, 102, 151, 182, 152, 243, 121, 111, 255, 33,
+ 243, 3, 141, 90, 86, 137, 75, 246, 200, 207, 221, 209, 250, 113, 132,
+ 139, 105, 155, 238, 11, 142, 46, 90, 250, 169, 120, 100, 159, 209, 179,
+ 215, 123, 219, 12, 167, 60, 99, 107, 215, 206, 238, 220, 107, 138, 251,
+ 199, 73, 178, 134, 35, 205, 143, 236, 105, 177, 82, 180, 101, 123, 124,
+ 193, 63, 251, 255, 25, 182, 126, 202, 228, 11, 23, 226, 163, 229, 95,
+ 134, 92, 119, 27, 219, 50, 230, 247, 173, 175, 219, 246, 219, 206, 254,
+ 223, 135, 131, 29, 31, 52, 203, 157, 85, 210, 224, 245, 151, 59, 59,
+ 75, 71, 60, 184, 19, 126, 248, 249, 111, 145, 215, 161, 249, 27, 226,
+ 86, 70, 31, 169, 243, 207, 169, 238, 103, 223, 39, 189, 109, 219, 215,
+ 121, 219, 170, 229, 49, 103, 195, 91, 93, 217, 213, 32, 195, 246, 245,
+ 154, 41, 247, 35, 3, 254, 155, 108, 183, 229, 229, 142, 130, 6, 62,
+ 23, 37, 77, 18, 65, 16, 237, 103, 59, 251, 76, 208, 241, 192, 182,
+ 219, 135, 197, 92, 30, 215, 193, 124, 126, 189, 169, 67, 118, 100, 191,
+ 169, 31, 117, 197, 106, 244, 11, 191, 157, 63, 34, 231, 13, 111, 116,
+ 125, 238, 251, 137, 85, 90, 53, 237, 250, 97, 144, 120, 91, 220, 24,
+ 89, 214, 197, 241, 181, 76, 236, 55, 86, 243, 89, 215, 188, 253, 197,
+ 79, 19, 23, 189, 127, 151, 191, 225, 169, 29, 125, 217, 61, 199, 181,
+ 190, 247, 148, 186, 125, 109, 234, 24, 37, 156, 253, 32, 250, 49, 108,
+ 94, 250, 137, 208, 91, 198, 244, 197, 55, 13, 102, 250, 117, 243, 217,
+ 214, 193, 118, 113, 157, 228, 33, 223, 63, 88, 217, 173, 58, 107, 245,
+ 60, 112, 100, 196, 22, 139, 129, 127, 167, 157, 90, 241, 81, 222, 169,
+ 90, 192, 143, 67, 133, 57, 201, 199, 46, 119, 106, 178, 188, 197, 187,
+ 7, 212, 214, 49, 169, 37, 174, 131, 78, 91, 90, 246, 110, 241, 180,
+ 249, 235, 167, 131, 221, 143, 103, 74, 114, 253, 146, 143, 22, 221, 221,
+ 21, 113, 239, 228, 137, 29, 141, 127, 139, 226, 79, 109, 186, 119, 254,
+ 227, 222, 16, 179, 244, 104, 179, 224, 189, 47, 115, 63, 117, 248, 116,
+ 196, 101, 249, 213, 246, 251, 231, 244, 29, 112, 249, 213, 63, 63, 67,
+ 141, 215, 61, 252, 183, 77, 106, 173, 115, 243, 235, 30, 249, 90, 152,
+ 59, 63, 45, 112, 97, 157, 180, 184, 120, 179, 162, 142, 5, 191, 70,
+ 78, 220, 189, 178, 221, 43, 191, 132, 125, 183, 188, 229, 119, 131, 63,
+ 217, 186, 125, 206, 61, 179, 121, 232, 147, 75, 163, 247, 245, 246, 241,
+ 179, 170, 119, 249, 68, 232, 152, 227, 77, 2, 47, 88, 239, 155, 236,
+ 121, 41, 216, 253, 99, 188, 253, 245, 119, 217, 123, 7, 197, 173, 60,
+ 184, 188, 66, 194, 4, 239, 71, 23, 54, 221, 123, 211, 120, 86, 142,
+ 125, 248, 250, 97, 179, 28, 211, 30, 141, 88, 24, 208, 98, 128, 248,
+ 223, 83, 5, 71, 7, 223, 246, 218, 238, 125, 161, 232, 85, 53, 201,
+ 206, 152, 23, 79, 47, 23, 15, 62, 209, 118, 221, 106, 155, 206, 255,
+ 172, 31, 95, 115, 104, 195, 215, 83, 159, 59, 68, 218, 94, 107, 188,
+ 54, 121, 153, 205, 158, 181, 78, 195, 229, 151, 172, 22, 63, 155, 250,
+ 205, 38, 167, 234, 151, 166, 15, 141, 179, 206, 213, 28, 84, 107, 122,
+ 101, 135, 3, 115, 179, 221, 11, 190, 175, 190, 86, 255, 196, 94, 175,
+ 13, 171, 107, 53, 90, 167, 184, 188, 42, 230, 193, 234, 31, 235, 103,
+ 6, 157, 58, 112, 239, 189, 71, 80, 221, 10, 97, 29, 98, 236, 62,
+ 58, 157, 220, 220, 200, 107, 71, 254, 192, 199, 201, 139, 246, 83, 105,
+ 98, 35, 135, 117, 78, 31, 127, 100, 57, 85, 122, 215, 225, 248, 222,
+ 45, 151, 54, 245, 170, 179, 176, 69, 68, 171, 58, 125, 135, 94, 190,
+ 183, 201, 220, 188, 225, 241, 172, 245, 173, 199, 213, 170, 176, 241, 244,
+ 209, 161, 31, 106, 223, 77, 30, 125, 247, 240, 155, 65, 79, 170, 120,
+ 117, 139, 15, 97, 230, 142, 57, 57, 164, 227, 243, 255, 26, 29, 174,
+ 178, 167, 123, 5, 207, 244, 189, 1, 29, 219, 62, 253, 190, 45, 59,
+ 123, 178, 233, 127, 116, 64, 223, 177, 25, 118, 187, 86, 133, 173, 29,
+ 88, 144, 59, 53, 33, 228, 198, 229, 241, 39, 86, 143, 108, 55, 218,
+ 163, 70, 114, 243, 131, 191, 230, 30, 157, 236, 94, 79, 210, 172, 209,
+ 173, 146, 139, 255, 210, 102, 199, 135, 239, 44, 233, 217, 215, 173, 91,
+ 167, 90, 195, 231, 159, 142, 236, 18, 55, 36, 250, 146, 151, 121, 238,
+ 186, 253, 81, 139, 93, 6, 137, 251, 206, 77, 155, 60, 189, 253, 198,
+ 36, 179, 101, 109, 90, 186, 214, 190, 182, 209, 173, 160, 224, 198, 29,
+ 201, 41, 102, 245, 217, 241, 187, 79, 237, 12, 255, 236, 88, 189, 119,
+ 235, 156, 38, 115, 63, 54, 244, 72, 104, 114, 111, 83, 243, 117, 61,
+ 3, 105, 177, 165, 217, 242, 232, 26, 73, 43, 134, 59, 207, 118, 24,
+ 127, 168, 93, 219, 245, 49, 141, 27, 206, 60, 189, 227, 212, 94, 23,
+ 35, 217, 252, 136, 103, 47, 247, 212, 176, 178, 146, 139, 254, 59, 54,
+ 168, 147, 73, 133, 85, 167, 92, 186, 216, 205, 106, 55, 223, 171, 112,
+ 90, 149, 140, 216, 142, 181, 106, 68, 137, 47, 223, 179, 105, 218, 34,
+ 189, 242, 19, 143, 197, 77, 188, 115, 135, 55, 181, 172, 16, 63, 59,
+ 74, 225, 118, 77, 84, 53, 181, 202, 85, 227, 36, 59, 170, 232, 227,
+ 251, 237, 35, 71, 7, 223, 47, 217, 55, 64, 18, 45, 241, 216, 221,
+ 243, 104, 203, 75, 157, 91, 249, 248, 25, 69, 101, 204, 140, 115, 91,
+ 223, 222, 119, 204, 58, 219, 185, 3, 99, 106, 244, 45, 30, 75, 217,
+ 228, 14, 14, 162, 140, 77, 58, 182, 171, 24, 63, 173, 160, 241, 212,
+ 89, 49, 126, 171, 36, 167, 175, 214, 245, 169, 108, 180, 190, 249, 162,
+ 253, 51, 70, 222, 95, 184, 255, 91, 188, 239, 248, 41, 39, 222, 53,
+ 120, 255, 178, 222, 40, 175, 35, 133, 149, 39, 30, 108, 126, 185, 193,
+ 219, 105, 133, 55, 198, 254, 206, 253, 60, 118, 239, 35, 199, 88, 241,
+ 152, 160, 236, 147, 45, 236, 6, 154, 77, 10, 123, 112, 113, 174, 223,
+ 204, 23, 63, 55, 251, 121, 196, 202, 44, 194, 250, 108, 72, 109, 181,
+ 190, 235, 236, 222, 31, 238, 12, 127, 180, 39, 189, 174, 131, 69, 204,
+ 231, 86, 19, 243, 135, 127, 61, 54, 180, 69, 99, 105, 137, 251, 158,
+ 97, 29, 140, 3, 94, 214, 48, 74, 188, 147, 86, 116, 121, 87, 237,
+ 246, 214, 217, 121, 138, 157, 15, 118, 122, 251, 157, 180, 49, 91, 121,
+ 245, 151, 185, 211, 156, 25, 11, 219, 50, 189, 243, 35, 154, 244, 111,
+ 212, 110, 130, 67, 181, 240, 78, 213, 106, 175, 104, 119, 160, 187, 185,
+ 209, 86, 231, 129, 223, 15, 95, 15, 221, 150, 48, 44, 157, 146, 52,
+ 54, 165, 166, 140, 22, 221, 235, 107, 85, 219, 100, 220, 30, 234, 109,
+ 224, 166, 171, 62, 93, 154, 12, 62, 211, 225, 88, 226, 102, 231, 5,
+ 210, 6, 206, 181, 188, 38, 43, 170, 20, 127, 255, 242, 239, 230, 61,
+ 107, 47, 154, 230, 13, 31, 96, 99, 229, 95, 233, 183, 168, 241, 177,
+ 121, 118, 163, 41, 209, 66, 227, 243, 127, 101, 108, 27, 241, 115, 70,
+ 233, 131, 45, 222, 169, 241, 146, 51, 93, 199, 212, 60, 243, 108, 251,
+ 6, 48, 231, 239, 111, 225, 180, 239, 218, 107, 115, 119, 73, 179, 53,
+ 169, 115, 26, 94, 124, 91, 56, 182, 229, 30, 191, 124, 255, 220, 187,
+ 157, 15, 189, 153, 37, 138, 115, 184, 251, 124, 234, 201, 253, 13, 156,
+ 103, 92, 109, 26, 178, 32, 209, 221, 207, 164, 183, 116, 131, 159, 123,
+ 162, 215, 23, 187, 160, 97, 206, 205, 198, 249, 14, 107, 75, 187, 196,
+ 13, 255, 58, 113, 225, 203, 118, 11, 214, 167, 167, 101, 250, 120, 152,
+ 207, 111, 19, 57, 101, 99, 73, 157, 65, 215, 198, 181, 221, 240, 172,
+ 235, 187, 253, 37, 125, 142, 57, 13, 222, 208, 221, 209, 113, 102, 140,
+ 212, 97, 187, 169, 149, 81, 226, 219, 152, 185, 91, 102, 84, 61, 56,
+ 97, 136, 183, 243, 173, 243, 46, 244, 224, 199, 27, 18, 210, 189, 223,
+ 207, 11, 26, 213, 189, 118, 247, 51, 237, 19, 221, 77, 35, 171, 198,
+ 181, 157, 248, 122, 194, 138, 124, 209, 248, 164, 2, 199, 85, 107, 123,
+ 55, 184, 93, 124, 37, 226, 115, 251, 97, 102, 183, 155, 210, 79, 191,
+ 5, 231, 158, 24, 243, 121, 205, 98, 123, 249, 18, 197, 192, 165, 169,
+ 159, 95, 118, 206, 205, 185, 247, 168, 85, 175, 194, 65, 149, 106, 86,
+ 173, 235, 251, 60, 188, 246, 209, 253, 147, 219, 38, 245, 79, 16, 53,
+ 148, 53, 221, 16, 17, 246, 109, 223, 36, 39, 219, 81, 255, 4, 220,
+ 238, 109, 101, 245, 120, 233, 207, 6, 35, 92, 179, 122, 60, 28, 49,
+ 183, 71, 166, 101, 197, 57, 199, 102, 212, 202, 74, 24, 185, 160, 243,
+ 236, 232, 54, 23, 141, 36, 115, 166, 130, 201, 218, 146, 252, 156, 218,
+ 199, 183, 156, 31, 23, 226, 179, 196, 183, 235, 212, 18, 233, 128, 165,
+ 201, 183, 71, 182, 184, 88, 181, 107, 241, 134, 51, 131, 199, 48, 23,
+ 199, 4, 62, 173, 211, 106, 182, 120, 115, 147, 172, 245, 209, 15, 178,
+ 122, 29, 88, 120, 172, 95, 130, 180, 119, 222, 193, 7, 55, 246, 254,
+ 117, 234, 219, 79, 143, 59, 37, 199, 87, 222, 153, 87, 117, 103, 159,
+ 173, 94, 110, 85, 92, 219, 59, 217, 81, 189, 71, 47, 168, 85, 239,
+ 165, 81, 225, 224, 196, 117, 37, 251, 150, 210, 247, 168, 154, 198, 179,
+ 147, 110, 57, 108, 79, 200, 127, 251, 216, 230, 235, 188, 195, 51, 38,
+ 121, 139, 100, 153, 226, 91, 77, 102, 237, 53, 53, 137, 55, 218, 85,
+ 91, 124, 33, 247, 219, 200, 30, 33, 67, 134, 95, 218, 125, 230, 205,
+ 253, 208, 79, 65, 123, 67, 186, 156, 141, 238, 44, 142, 125, 248, 182,
+ 175, 232, 174, 168, 185, 155, 141, 91, 243, 255, 29, 95, 190, 57, 174,
+ 209, 206, 5, 207, 58, 153, 182, 106, 92, 177, 75, 193, 182, 26, 83,
+ 246, 124, 172, 208, 162, 145, 236, 94, 196, 162, 7, 7, 2, 186, 214,
+ 204, 61, 19, 87, 177, 201, 243, 156, 3, 162, 61, 205, 255, 238, 20,
+ 222, 35, 174, 244, 184, 104, 89, 208, 200, 1, 35, 163, 35, 171, 85,
+ 118, 185, 112, 161, 145, 89, 98, 236, 170, 248, 109, 182, 255, 181, 218,
+ 251, 109, 102, 192, 233, 208, 53, 171, 223, 28, 168, 248, 52, 111, 70,
+ 171, 87, 237, 122, 87, 105, 92, 101, 203, 69, 183, 6, 115, 59, 121,
+ 30, 144, 58, 250, 180, 124, 150, 178, 126, 203, 242, 240, 112, 39, 179,
+ 37, 77, 159, 5, 84, 28, 238, 215, 125, 234, 161, 26, 199, 143, 111,
+ 78, 46, 25, 187, 106, 179, 213, 18, 111, 187, 86, 177, 125, 143, 63,
+ 63, 222, 232, 224, 228, 153, 54, 169, 223, 199, 175, 184, 109, 237, 63,
+ 103, 78, 230, 138, 196, 223, 183, 123, 125, 251, 39, 222, 120, 198, 162,
+ 105, 51, 94, 245, 60, 249, 246, 233, 153, 1, 222, 247, 230, 39, 91,
+ 173, 188, 64, 111, 27, 191, 126, 213, 78, 79, 153, 209, 126, 139, 210,
+ 206, 219, 106, 255, 251, 186, 212, 105, 113, 78, 243, 225, 166, 238, 43,
+ 138, 162, 91, 245, 255, 45, 58, 149, 60, 103, 246, 203, 152, 195, 81,
+ 95, 234, 87, 219, 108, 190, 39, 230, 140, 251, 155, 27, 125, 171, 54,
+ 236, 115, 91, 90, 82, 251, 221, 171, 43, 243, 140, 127, 158, 63, 56,
+ 112, 252, 186, 148, 85, 45, 170, 155, 138, 172, 2, 54, 111, 206, 79,
+ 12, 61, 254, 122, 251, 222, 229, 249, 171, 123, 59, 216, 15, 41, 76,
+ 218, 189, 173, 195, 216, 157, 253, 118, 120, 135, 251, 109, 42, 168, 187,
+ 234, 163, 104, 127, 231, 161, 46, 251, 50, 82, 94, 229, 83, 111, 222,
+ 36, 61, 252, 178, 254, 135, 104, 208, 225, 235, 181, 31, 87, 63, 237,
+ 120, 39, 204, 113, 214, 187, 169, 187, 50, 102, 54, 159, 184, 186, 119,
+ 212, 132, 158, 78, 169, 159, 134, 238, 216, 184, 175, 78, 235, 5, 135,
+ 189, 147, 214, 109, 148, 157, 11, 245, 184, 18, 49, 244, 249, 179, 156,
+ 55, 153, 131, 189, 253, 78, 125, 152, 210, 98, 74, 183, 184, 254, 133,
+ 57, 143, 194, 220, 223, 110, 9, 189, 84, 127, 252, 184, 227, 111, 206,
+ 135, 126, 159, 188, 109, 202, 250, 253, 61, 115, 166, 53, 219, 151, 96,
+ 213, 36, 52, 118, 130, 231, 188, 78, 38, 135, 247, 49, 117, 38, 44,
+ 235, 148, 54, 35, 230, 233, 199, 32, 233, 137, 44, 19, 187, 9, 230,
+ 30, 3, 138, 254, 123, 126, 123, 255, 178, 213, 107, 42, 184, 181, 140,
+ 18, 79, 171, 85, 81, 58, 111, 88, 228, 30, 155, 214, 173, 44, 215,
+ 52, 152, 34, 94, 25, 85, 117, 234, 233, 161, 73, 3, 155, 212, 114,
+ 219, 118, 98, 231, 215, 13, 117, 69, 33, 83, 58, 126, 249, 250, 170,
+ 106, 157, 191, 55, 154, 123, 172, 220, 248, 246, 175, 180, 123, 179, 154,
+ 47, 250, 175, 199, 92, 219, 27, 9, 183, 38, 220, 220, 57, 75, 225,
+ 246, 52, 40, 236, 208, 198, 161, 247, 199, 75, 63, 199, 221, 205, 61,
+ 40, 189, 107, 83, 84, 209, 168, 246, 79, 143, 31, 135, 95, 254, 116,
+ 188, 75, 215, 170, 148, 215, 228, 232, 202, 168, 95, 247, 188, 122, 13,
+ 203, 95, 27, 46, 110, 180, 114, 199, 202, 160, 225, 209, 103, 223, 75,
+ 39, 126, 10, 127, 59, 34, 57, 151, 121, 122, 110, 150, 241, 236, 235,
+ 119, 134, 86, 189, 102, 250, 209, 228, 148, 135, 201, 249, 78, 53, 71,
+ 79, 222, 112, 105, 204, 147, 0, 203, 39, 174, 221, 123, 90, 119, 108,
+ 177, 98, 137, 243, 84, 251, 244, 137, 129, 138, 106, 219, 86, 14, 62,
+ 186, 225, 221, 203, 21, 166, 239, 237, 83, 236, 75, 11, 124, 19, 143,
+ 184, 28, 107, 231, 60, 245, 228, 178, 121, 51, 43, 12, 75, 252, 149,
+ 211, 106, 101, 190, 111, 82, 240, 141, 202, 53, 207, 70, 207, 175, 212,
+ 196, 253, 75, 80, 76, 235, 106, 212, 170, 243, 173, 130, 7, 196, 108,
+ 167, 42, 57, 228, 159, 93, 18, 243, 56, 251, 120, 211, 0, 217, 147,
+ 95, 55, 187, 82, 185, 111, 98, 154, 250, 44, 190, 55, 59, 60, 50,
+ 43, 217, 184, 223, 58, 243, 113, 83, 15, 209, 180, 164, 32, 125, 142,
+ 172, 184, 209, 177, 153, 87, 171, 191, 148, 88, 42, 102, 173, 122, 155,
+ 187, 195, 248, 131, 169, 213, 16, 103, 143, 135, 119, 134, 153, 26, 27,
+ 129, 121, 99, 222, 163, 130, 201, 162, 132, 126, 11, 159, 84, 252, 57,
+ 173, 249, 213, 234, 171, 51, 158, 236, 172, 155, 223, 116, 89, 109, 241,
+ 171, 5, 197, 233, 143, 197, 97, 14, 205, 103, 53, 153, 186, 127, 198,
+ 134, 233, 99, 168, 189, 159, 134, 12, 24, 176, 55, 125, 229, 193, 53,
+ 223, 166, 229, 180, 9, 218, 208, 102, 141, 113, 85, 115, 135, 188, 235,
+ 155, 142, 124, 252, 100, 187, 224, 250, 240, 249, 183, 226, 187, 54, 45,
+ 242, 253, 181, 171, 120, 230, 237, 175, 63, 36, 109, 174, 37, 172, 246,
+ 122, 119, 110, 192, 181, 163, 9, 245, 250, 230, 141, 56, 215, 196, 170,
+ 253, 247, 69, 205, 82, 170, 117, 232, 91, 244, 241, 229, 193, 223, 119,
+ 69, 34, 81, 119, 90, 36, 10, 6, 255, 122, 22, 77, 20, 215, 99,
+ 47, 8, 147, 39, 114, 119, 232, 137, 148, 109, 186, 251, 78, 158, 16,
+ 234, 171, 253, 190, 57, 68, 73, 0, 183, 16, 70, 36, 146, 73, 69,
+ 162, 68, 64, 87, 3, 180, 72, 202, 119, 103, 29, 146, 15, 101, 214,
+ 35, 56, 193, 247, 41, 43, 223, 214, 206, 206, 94, 219, 125, 119, 34,
+ 145, 131, 232, 218, 213, 171, 174, 34, 209, 69, 86, 166, 68, 39, 249,
+ 253, 64, 171, 116, 240, 111, 78, 206, 68, 113, 147, 63, 120, 162, 54,
+ 253, 124, 39, 135, 252, 249, 220, 20, 223, 49, 134, 46, 176, 131, 122,
+ 163, 63, 248, 31, 69, 169, 236, 16, 194, 108, 74, 176, 114, 83, 251,
+ 255, 198, 38, 34, 246, 61, 193, 59, 118, 98, 109, 70, 81, 255, 215,
+ 123, 2, 123, 123, 2, 155, 65, 137, 192, 142, 230, 232, 59, 250, 76,
+ 18, 171, 183, 161, 199, 205, 152, 52, 117, 138, 173, 239, 140, 96, 223,
+ 233, 156, 53, 177, 205, 129, 13, 60, 101, 234, 223, 30, 254, 71, 119,
+ 87, 253, 11, 239, 5, 244, 100, 219, 181, 97, 251, 121, 70, 113, 237,
+ 115, 82, 254, 236, 251, 39, 175, 250, 74, 203, 25, 107, 176, 181, 247,
+ 188, 62, 29, 176, 140, 40, 78, 70, 14, 120, 39, 40, 83, 121, 31,
+ 226, 42, 93, 100, 52, 208, 42, 35, 188, 210, 207, 20, 36, 3, 242,
+ 197, 122, 64, 25, 172, 46, 118, 33, 147, 116, 144, 209, 80, 171, 140,
+ 101, 107, 218, 186, 98, 61, 8, 25, 34, 86, 166, 210, 83, 236, 116,
+ 145, 97, 165, 85, 134, 245, 133, 72, 41, 148, 81, 196, 218, 221, 154,
+ 245, 199, 226, 132, 101, 167, 160, 29, 145, 63, 34, 58, 212, 113, 9,
+ 205, 61, 47, 139, 99, 37, 119, 99, 69, 171, 250, 76, 159, 201, 29,
+ 83, 88, 175, 103, 80, 251, 138, 223, 189, 153, 5, 204, 41, 222, 190,
+ 197, 98, 63, 230, 159, 156, 56, 59, 213, 211, 96, 70, 218, 254, 111,
+ 37, 93, 249, 243, 92, 198, 58, 227, 128, 29, 95, 223, 159, 11, 99,
+ 25, 215, 238, 13, 216, 54, 43, 49, 221, 38, 127, 61, 241, 92, 115,
+ 95, 100, 3, 232, 23, 164, 13, 224, 119, 70, 54, 64, 52, 180, 1,
+ 247, 92, 187, 13, 182, 135, 60, 180, 71, 54, 64, 237, 161, 13, 150,
+ 111, 156, 154, 42, 100, 3, 231, 190, 14, 105, 200, 6, 203, 183, 210,
+ 105, 200, 6, 11, 55, 15, 75, 19, 178, 129, 111, 184, 60, 21, 217,
+ 0, 209, 208, 6, 220, 115, 1, 27, 0, 191, 69, 54, 248, 12, 108,
+ 0, 253, 16, 217, 0, 209, 109, 59, 45, 161, 185, 231, 154, 249, 209,
+ 45, 234, 51, 158, 54, 245, 178, 145, 13, 80, 123, 57, 176, 1, 149,
+ 179, 131, 183, 111, 35, 96, 131, 59, 253, 66, 221, 144, 13, 186, 198,
+ 199, 40, 233, 206, 192, 6, 242, 246, 107, 220, 248, 250, 126, 6, 54,
+ 200, 189, 98, 236, 134, 108, 128, 232, 70, 192, 6, 220, 115, 126, 27,
+ 64, 92, 145, 126, 0, 113, 130, 108, 128, 232, 64, 224, 7, 220, 115,
+ 205, 252, 174, 0, 63, 152, 249, 119, 140, 20, 217, 0, 181, 175, 10,
+ 108, 80, 218, 59, 130, 183, 239, 103, 96, 131, 150, 38, 179, 165, 200,
+ 6, 33, 1, 97, 74, 186, 26, 176, 193, 163, 240, 89, 82, 33, 63,
+ 176, 127, 17, 46, 69, 54, 64, 116, 107, 96, 3, 238, 185, 230, 190,
+ 104, 12, 128, 113, 31, 141, 1, 33, 230, 147, 196, 20, 49, 158, 255,
+ 49, 6, 56, 168, 143, 1, 20, 232, 235, 249, 215, 36, 193, 49, 0,
+ 182, 67, 113, 77, 46, 225, 218, 43, 60, 39, 233, 56, 6, 24, 105,
+ 140, 107, 16, 239, 72, 6, 228, 139, 100, 80, 128, 166, 216, 241, 44,
+ 68, 39, 25, 13, 180, 202, 128, 120, 194, 122, 16, 50, 160, 222, 72,
+ 23, 159, 154, 186, 142, 1, 154, 101, 64, 127, 197, 99, 192, 95, 147,
+ 212, 198, 0, 138, 149, 81, 100, 174, 235, 24, 160, 89, 6, 244, 7,
+ 40, 195, 133, 181, 187, 53, 219, 198, 236, 221, 223, 114, 46, 110, 202,
+ 164, 136, 94, 232, 150, 73, 241, 197, 83, 35, 35, 35, 99, 196, 47,
+ 164, 12, 63, 46, 6, 201, 164, 136, 134, 252, 248, 98, 19, 201, 15,
+ 218, 147, 228, 199, 225, 89, 38, 69, 52, 228, 199, 135, 115, 146, 31,
+ 180, 29, 201, 143, 195, 134, 76, 138, 104, 200, 143, 15, 51, 144, 31,
+ 194, 12, 196, 9, 194, 140, 39, 24, 79, 201, 220, 233, 15, 204, 116,
+ 84, 199, 76, 136, 17, 240, 27, 90, 24, 51, 176, 29, 242, 131, 34,
+ 17, 215, 222, 147, 214, 15, 51, 163, 173, 162, 112, 222, 4, 249, 182,
+ 193, 23, 253, 78, 18, 67, 153, 74, 92, 82, 250, 97, 166, 94, 117,
+ 9, 198, 76, 8, 33, 3, 234, 141, 116, 9, 161, 244, 195, 140, 44,
+ 102, 56, 206, 155, 32, 95, 18, 51, 33, 72, 134, 104, 162, 94, 152,
+ 89, 180, 51, 18, 99, 6, 218, 221, 90, 99, 206, 47, 147, 66, 155,
+ 114, 57, 189, 182, 251, 182, 213, 125, 18, 218, 88, 27, 63, 104, 191,
+ 242, 242, 11, 225, 225, 7, 109, 85, 110, 126, 162, 137, 90, 249, 65,
+ 187, 232, 202, 15, 97, 6, 226, 4, 97, 38, 241, 32, 240, 53, 115,
+ 30, 204, 116, 82, 199, 76, 74, 252, 68, 177, 36, 90, 24, 51, 176,
+ 29, 242, 3, 187, 120, 238, 219, 167, 68, 25, 110, 156, 177, 35, 100,
+ 36, 130, 119, 74, 97, 229, 80, 81, 134, 27, 103, 32, 95, 36, 3,
+ 234, 141, 116, 201, 145, 25, 110, 156, 145, 68, 171, 99, 38, 145, 181,
+ 175, 143, 204, 112, 227, 12, 180, 59, 242, 161, 68, 170, 131, 198, 113,
+ 38, 62, 109, 63, 165, 75, 222, 238, 194, 218, 152, 228, 167, 105, 156,
+ 129, 252, 116, 201, 129, 93, 88, 123, 90, 227, 216, 212, 65, 227, 56,
+ 35, 79, 221, 79, 233, 146, 79, 186, 176, 182, 35, 223, 79, 211, 56,
+ 35, 3, 239, 167, 107, 110, 6, 113, 130, 48, 227, 179, 23, 228, 90,
+ 41, 60, 185, 153, 99, 153, 234, 10, 232, 155, 184, 95, 24, 51, 176,
+ 29, 246, 231, 3, 92, 123, 187, 253, 250, 97, 134, 156, 159, 67, 190,
+ 216, 159, 1, 13, 101, 42, 109, 187, 79, 63, 204, 144, 243, 115, 9,
+ 33, 3, 234, 141, 116, 241, 220, 167, 31, 102, 200, 249, 57, 228, 75,
+ 98, 70, 194, 202, 80, 236, 213, 15, 51, 104, 126, 238, 194, 218, 29,
+ 249, 144, 204, 71, 44, 191, 55, 112, 139, 99, 217, 249, 121, 191, 196,
+ 13, 84, 255, 140, 204, 195, 186, 196, 113, 104, 99, 146, 223, 160, 27,
+ 255, 164, 151, 157, 235, 66, 126, 133, 55, 207, 118, 210, 133, 159, 39,
+ 193, 175, 245, 40, 177, 220, 110, 227, 195, 19, 101, 231, 141, 137, 25,
+ 27, 168, 87, 83, 174, 186, 234, 52, 14, 238, 37, 198, 45, 240, 126,
+ 85, 183, 70, 253, 49, 7, 155, 191, 125, 3, 101, 179, 125, 158, 78,
+ 185, 25, 196, 9, 198, 204, 78, 224, 7, 7, 121, 198, 153, 206, 234,
+ 152, 81, 36, 79, 18, 251, 236, 17, 198, 12, 108, 135, 252, 192, 39,
+ 153, 104, 159, 164, 43, 102, 42, 104, 244, 3, 82, 134, 15, 33, 67,
+ 1, 222, 73, 193, 202, 73, 252, 87, 87, 204, 8, 203, 128, 124, 177,
+ 30, 128, 70, 186, 80, 255, 232, 138, 25, 29, 244, 216, 163, 142, 25,
+ 5, 107, 95, 197, 78, 93, 49, 163, 77, 134, 76, 137, 153, 118, 70,
+ 42, 187, 91, 43, 91, 130, 248, 223, 166, 157, 156, 108, 131, 40, 42,
+ 37, 134, 226, 203, 85, 96, 220, 149, 15, 44, 161, 126, 244, 125, 114,
+ 136, 141, 128, 116, 82, 172, 106, 92, 146, 228, 249, 210, 22, 199, 159,
+ 117, 228, 235, 91, 84, 59, 142, 94, 21, 176, 137, 197, 106, 18, 174,
+ 159, 213, 126, 121, 142, 110, 237, 124, 236, 48, 95, 223, 183, 245, 10,
+ 233, 161, 116, 245, 163, 108, 165, 152, 249, 175, 203, 173, 35, 202, 90,
+ 113, 73, 37, 230, 81, 227, 204, 35, 124, 125, 75, 77, 106, 48, 92,
+ 173, 206, 2, 211, 33, 47, 172, 24, 161, 26, 30, 178, 31, 244, 41,
+ 67, 217, 207, 161, 250, 41, 7, 100, 191, 93, 57, 170, 113, 24, 218,
+ 143, 57, 97, 126, 72, 200, 126, 182, 23, 118, 164, 35, 251, 161, 216,
+ 4, 237, 103, 221, 254, 84, 39, 33, 251, 45, 217, 106, 209, 25, 217,
+ 47, 124, 215, 3, 71, 100, 191, 196, 105, 103, 29, 133, 236, 199, 213,
+ 249, 44, 48, 13, 237, 39, 84, 255, 67, 246, 131, 120, 65, 246, 75,
+ 109, 173, 217, 126, 13, 116, 176, 223, 245, 126, 37, 212, 214, 174, 191,
+ 93, 145, 253, 130, 76, 77, 148, 121, 135, 223, 93, 95, 58, 38, 184,
+ 34, 111, 14, 50, 205, 34, 142, 182, 90, 116, 244, 4, 178, 31, 138,
+ 197, 217, 111, 207, 209, 227, 34, 46, 241, 214, 225, 238, 88, 22, 210,
+ 73, 61, 76, 164, 200, 126, 181, 59, 94, 86, 202, 154, 45, 170, 204,
+ 28, 51, 57, 194, 43, 215, 198, 180, 6, 195, 213, 8, 45, 48, 125,
+ 236, 185, 21, 35, 84, 59, 68, 246, 131, 177, 64, 221, 255, 100, 82,
+ 245, 53, 18, 228, 127, 50, 222, 188, 41, 11, 248, 223, 239, 109, 40,
+ 183, 178, 163, 71, 23, 168, 232, 182, 192, 255, 78, 180, 229, 175, 195,
+ 253, 6, 254, 103, 180, 14, 141, 61, 73, 184, 230, 55, 28, 248, 95,
+ 254, 145, 121, 188, 125, 75, 128, 255, 57, 116, 27, 143, 237, 87, 104,
+ 23, 164, 164, 221, 128, 255, 109, 138, 153, 204, 47, 23, 248, 31, 87,
+ 95, 180, 192, 116, 0, 240, 63, 161, 186, 35, 30, 243, 118, 114, 99,
+ 158, 124, 43, 136, 227, 123, 121, 198, 188, 174, 101, 198, 188, 29, 160,
+ 253, 118, 29, 198, 188, 29, 196, 88, 177, 131, 107, 95, 148, 104, 184,
+ 185, 149, 15, 33, 67, 1, 222, 73, 193, 202, 145, 37, 26, 110, 110,
+ 5, 249, 98, 61, 0, 141, 116, 73, 217, 102, 184, 185, 149, 207, 246,
+ 50, 99, 30, 107, 95, 106, 155, 225, 230, 86, 208, 238, 250, 206, 173,
+ 200, 60, 76, 150, 168, 255, 220, 138, 228, 7, 237, 169, 239, 220, 138,
+ 228, 71, 109, 211, 127, 110, 69, 230, 137, 16, 39, 8, 51, 178, 141,
+ 192, 15, 118, 242, 96, 166, 91, 153, 186, 55, 232, 43, 255, 91, 135,
+ 186, 247, 86, 162, 246, 181, 133, 107, 159, 179, 89, 87, 204, 152, 104,
+ 158, 147, 52, 201, 227, 234, 222, 91, 136, 186, 55, 160, 161, 76, 165,
+ 207, 109, 210, 21, 51, 154, 101, 36, 126, 95, 152, 134, 245, 32, 100,
+ 64, 189, 145, 46, 69, 9, 186, 98, 70, 179, 140, 103, 230, 71, 48,
+ 102, 32, 95, 181, 186, 55, 178, 87, 130, 174, 152, 209, 44, 99, 65,
+ 143, 169, 74, 204, 164, 179, 118, 183, 86, 182, 20, 137, 126, 44, 110,
+ 42, 133, 118, 196, 115, 23, 150, 182, 82, 236, 38, 158, 107, 142, 187,
+ 207, 155, 228, 73, 35, 22, 62, 70, 109, 168, 183, 214, 79, 149, 180,
+ 199, 210, 113, 212, 175, 30, 175, 121, 251, 142, 109, 113, 128, 226, 248,
+ 43, 48, 237, 176, 208, 140, 230, 147, 139, 176, 144, 206, 126, 91, 82,
+ 15, 248, 173, 144, 30, 136, 134, 122, 112, 207, 181, 235, 97, 118, 117,
+ 25, 106, 67, 217, 255, 111, 121, 26, 210, 163, 228, 246, 170, 52, 33,
+ 61, 56, 254, 10, 76, 67, 61, 248, 228, 146, 122, 64, 255, 65, 122,
+ 248, 44, 105, 42, 133, 254, 128, 244, 64, 244, 139, 71, 187, 137, 231,
+ 154, 223, 229, 73, 163, 60, 233, 145, 159, 89, 168, 13, 181, 100, 196,
+ 73, 37, 189, 120, 201, 56, 106, 151, 253, 121, 222, 190, 78, 64, 15,
+ 142, 191, 2, 211, 109, 128, 30, 124, 114, 73, 61, 68, 132, 30, 149,
+ 129, 30, 208, 231, 144, 30, 136, 174, 5, 190, 7, 247, 92, 243, 187,
+ 108, 0, 223, 99, 211, 81, 156, 47, 80, 47, 66, 85, 116, 91, 240,
+ 61, 222, 54, 8, 230, 237, 59, 2, 232, 193, 241, 87, 96, 218, 30,
+ 232, 193, 39, 151, 140, 137, 48, 14, 162, 152, 72, 173, 5, 56, 223,
+ 170, 61, 38, 218, 219, 149, 217, 87, 3, 250, 202, 214, 11, 199, 68,
+ 216, 14, 225, 92, 182, 129, 107, 111, 190, 94, 191, 60, 194, 190, 162,
+ 145, 61, 146, 1, 249, 226, 88, 2, 101, 108, 100, 231, 206, 235, 244,
+ 203, 35, 18, 190, 108, 195, 49, 81, 68, 200, 128, 122, 35, 93, 236,
+ 214, 233, 151, 71, 72, 253, 238, 226, 152, 8, 249, 146, 49, 81, 196,
+ 202, 144, 175, 213, 47, 143, 56, 121, 33, 0, 231, 17, 208, 238, 218,
+ 234, 252, 208, 166, 229, 93, 55, 128, 54, 214, 198, 15, 218, 175, 188,
+ 252, 236, 120, 248, 65, 91, 149, 151, 31, 180, 157, 54, 126, 208, 46,
+ 229, 93, 215, 128, 56, 193, 235, 26, 191, 129, 31, 108, 228, 193, 76,
+ 153, 61, 84, 242, 53, 96, 188, 94, 45, 140, 25, 216, 14, 143, 241,
+ 107, 136, 60, 98, 149, 225, 114, 111, 138, 144, 33, 7, 239, 36, 103,
+ 229, 248, 172, 50, 92, 238, 13, 249, 98, 61, 0, 141, 116, 41, 138,
+ 55, 92, 238, 77, 173, 86, 199, 140, 156, 181, 175, 44, 222, 112, 185,
+ 55, 180, 187, 33, 215, 53, 124, 86, 25, 118, 93, 3, 218, 211, 144,
+ 235, 26, 178, 120, 3, 175, 107, 252, 38, 106, 180, 63, 129, 31, 172,
+ 229, 193, 76, 153, 61, 39, 18, 208, 55, 177, 84, 135, 117, 141, 223,
+ 196, 122, 192, 47, 98, 93, 163, 84, 63, 204, 248, 165, 189, 229, 214,
+ 53, 126, 17, 235, 26, 128, 134, 50, 149, 182, 45, 209, 15, 51, 65,
+ 195, 214, 96, 204, 72, 8, 25, 80, 111, 164, 139, 103, 137, 126, 152,
+ 185, 226, 122, 145, 91, 215, 40, 45, 179, 174, 193, 202, 80, 252, 212,
+ 15, 51, 162, 243, 17, 220, 186, 70, 169, 246, 184, 11, 109, 90, 238,
+ 56, 94, 162, 157, 31, 180, 95, 121, 249, 121, 242, 240, 131, 182, 42,
+ 247, 250, 254, 79, 237, 252, 160, 93, 202, 59, 206, 64, 156, 32, 204,
+ 20, 125, 0, 126, 240, 91, 3, 102, 198, 249, 134, 134, 204, 156, 110,
+ 27, 60, 193, 95, 189, 198, 83, 12, 230, 183, 63, 116, 168, 241, 20,
+ 19, 181, 145, 98, 34, 55, 251, 166, 43, 102, 42, 107, 244, 131, 111,
+ 79, 114, 92, 112, 109, 132, 144, 161, 0, 239, 164, 96, 229, 200, 63,
+ 235, 138, 25, 205, 50, 22, 220, 153, 142, 101, 64, 190, 88, 15, 64,
+ 35, 93, 66, 62, 234, 138, 25, 205, 50, 228, 189, 27, 102, 99, 61,
+ 126, 148, 169, 241, 176, 246, 205, 121, 171, 43, 102, 52, 203, 232, 245,
+ 116, 190, 18, 51, 13, 141, 85, 118, 183, 86, 182, 84, 237, 79, 132,
+ 118, 68, 126, 131, 104, 143, 244, 181, 52, 247, 92, 115, 220, 253, 60,
+ 160, 27, 83, 191, 205, 57, 182, 77, 63, 6, 181, 55, 206, 26, 200,
+ 12, 113, 254, 143, 183, 239, 47, 198, 139, 185, 121, 253, 62, 219, 102,
+ 24, 99, 237, 247, 144, 237, 59, 146, 153, 253, 249, 145, 64, 95, 31,
+ 102, 173, 248, 49, 219, 102, 60, 243, 174, 201, 45, 85, 223, 8, 127,
+ 38, 98, 225, 21, 254, 190, 81, 147, 152, 43, 235, 15, 177, 109, 130,
+ 153, 112, 201, 191, 108, 223, 41, 76, 135, 228, 141, 188, 125, 127, 71,
+ 77, 99, 130, 150, 174, 96, 219, 204, 96, 204, 219, 203, 216, 190, 179,
+ 152, 128, 109, 19, 4, 228, 206, 97, 110, 212, 114, 100, 219, 204, 103,
+ 34, 206, 180, 84, 210, 70, 17, 50, 230, 81, 139, 42, 2, 125, 99,
+ 152, 129, 81, 205, 216, 54, 177, 204, 167, 253, 214, 172, 220, 197, 204,
+ 134, 123, 173, 5, 250, 46, 99, 14, 37, 181, 97, 219, 172, 196, 116,
+ 198, 167, 120, 226, 185, 246, 113, 26, 250, 11, 196, 16, 233, 47, 16,
+ 19, 120, 30, 202, 210, 208, 95, 184, 231, 218, 253, 229, 234, 127, 67,
+ 176, 191, 160, 246, 208, 95, 106, 252, 51, 135, 183, 111, 41, 240, 151,
+ 232, 90, 139, 176, 191, 36, 117, 93, 142, 253, 229, 127, 99, 86, 9,
+ 250, 203, 171, 53, 27, 177, 191, 52, 250, 185, 14, 251, 75, 161, 116,
+ 173, 160, 191, 100, 95, 88, 138, 253, 229, 80, 238, 2, 236, 47, 3,
+ 47, 132, 11, 244, 157, 198, 84, 233, 22, 130, 253, 197, 114, 232, 56,
+ 236, 47, 45, 103, 14, 17, 244, 23, 233, 14, 26, 251, 203, 241, 182,
+ 78, 216, 95, 82, 156, 109, 4, 253, 229, 179, 79, 7, 236, 47, 131,
+ 69, 182, 216, 95, 210, 182, 181, 19, 244, 151, 111, 152, 255, 74, 76,
+ 67, 127, 249, 38, 32, 23, 249, 11, 140, 135, 164, 191, 192, 248, 134,
+ 252, 5, 209, 157, 128, 191, 112, 207, 53, 243, 59, 9, 252, 229, 138,
+ 159, 17, 222, 3, 142, 218, 155, 1, 127, 105, 177, 183, 41, 111, 223,
+ 239, 192, 95, 102, 56, 58, 102, 35, 127, 57, 145, 226, 170, 164, 127,
+ 103, 142, 100, 222, 217, 184, 243, 246, 173, 220, 221, 135, 145, 191, 252,
+ 43, 27, 249, 139, 127, 137, 135, 146, 182, 6, 254, 226, 55, 134, 230,
+ 237, 107, 20, 61, 137, 185, 84, 161, 117, 54, 242, 23, 139, 150, 150,
+ 42, 26, 248, 203, 112, 247, 74, 188, 125, 197, 209, 211, 152, 227, 117,
+ 222, 101, 33, 127, 153, 58, 247, 170, 146, 54, 5, 254, 146, 240, 48,
+ 57, 139, 175, 111, 30, 240, 151, 181, 127, 5, 100, 33, 127, 57, 115,
+ 154, 86, 210, 69, 225, 50, 102, 212, 208, 183, 153, 124, 125, 127, 2,
+ 127, 113, 238, 101, 149, 133, 252, 229, 80, 96, 173, 44, 228, 47, 157,
+ 86, 84, 205, 18, 242, 151, 122, 38, 239, 50, 145, 191, 32, 26, 250,
+ 11, 247, 156, 223, 95, 224, 216, 70, 250, 11, 28, 171, 144, 191, 32,
+ 26, 198, 23, 238, 185, 102, 126, 159, 128, 191, 172, 50, 139, 192, 251,
+ 229, 81, 123, 19, 224, 47, 137, 187, 249, 251, 194, 248, 18, 145, 131,
+ 214, 227, 134, 49, 227, 166, 170, 104, 24, 95, 122, 85, 231, 95, 167,
+ 131, 241, 229, 81, 248, 92, 41, 242, 151, 192, 34, 21, 109, 2, 252,
+ 229, 130, 139, 64, 95, 16, 95, 190, 134, 206, 199, 251, 244, 59, 213,
+ 82, 205, 117, 140, 128, 191, 132, 166, 134, 75, 133, 226, 139, 43, 141,
+ 244, 157, 193, 72, 146, 35, 216, 190, 179, 24, 147, 218, 145, 82, 161,
+ 248, 146, 184, 16, 181, 153, 207, 252, 62, 16, 41, 197, 227, 145, 192,
+ 122, 40, 140, 47, 109, 255, 135, 250, 198, 50, 230, 215, 85, 52, 244,
+ 151, 175, 215, 133, 228, 46, 99, 92, 30, 68, 226, 179, 5, 136, 134,
+ 254, 194, 61, 231, 159, 231, 193, 60, 21, 229, 172, 241, 133, 32, 15,
+ 251, 201, 155, 179, 42, 15, 153, 225, 61, 188, 160, 111, 206, 27, 29,
+ 246, 73, 127, 32, 246, 73, 23, 113, 237, 125, 222, 232, 55, 207, 131,
+ 99, 46, 222, 39, 93, 68, 236, 251, 7, 24, 128, 50, 149, 152, 125,
+ 173, 223, 60, 15, 198, 105, 188, 239, 255, 45, 39, 3, 234, 141, 116,
+ 145, 189, 214, 111, 158, 7, 177, 141, 207, 176, 189, 81, 207, 89, 61,
+ 217, 92, 213, 252, 181, 126, 243, 60, 232, 15, 184, 150, 241, 70, 125,
+ 175, 61, 151, 187, 200, 164, 136, 126, 194, 100, 82, 124, 57, 141, 218,
+ 222, 253, 215, 234, 252, 184, 177, 13, 228, 192, 44, 13, 249, 241, 141,
+ 121, 106, 235, 156, 101, 248, 113, 177, 79, 38, 69, 52, 228, 199, 23,
+ 19, 73, 126, 230, 101, 248, 113, 216, 144, 73, 17, 13, 249, 241, 97,
+ 134, 156, 231, 65, 156, 224, 179, 5, 207, 129, 31, 124, 16, 194, 140,
+ 3, 254, 30, 230, 160, 111, 252, 75, 97, 204, 192, 118, 200, 15, 226,
+ 95, 113, 237, 37, 47, 13, 135, 25, 200, 23, 201, 48, 7, 52, 148,
+ 169, 92, 103, 127, 97, 56, 204, 152, 19, 50, 160, 222, 72, 23, 234,
+ 133, 225, 48, 3, 249, 146, 152, 49, 103, 101, 228, 60, 55, 28, 102,
+ 160, 221, 113, 173, 192, 116, 126, 182, 38, 204, 136, 194, 26, 235, 140,
+ 25, 104, 99, 146, 159, 38, 204, 64, 126, 186, 98, 134, 42, 195, 79,
+ 19, 102, 32, 63, 93, 49, 3, 109, 71, 242, 211, 132, 25, 200, 79,
+ 87, 204, 64, 156, 32, 204, 152, 63, 1, 126, 80, 40, 132, 153, 142,
+ 220, 25, 219, 130, 73, 98, 207, 103, 194, 152, 129, 237, 240, 24, 80,
+ 64, 156, 97, 123, 106, 56, 204, 120, 18, 50, 114, 192, 59, 229, 176,
+ 114, 66, 158, 26, 14, 51, 144, 47, 214, 3, 208, 88, 151, 167, 134,
+ 195, 140, 231, 51, 117, 204, 228, 176, 246, 141, 127, 98, 56, 204, 64,
+ 187, 235, 139, 25, 178, 198, 29, 242, 84, 127, 204, 144, 252, 68, 79,
+ 245, 199, 12, 201, 15, 218, 78, 95, 204, 144, 185, 25, 196, 9, 174,
+ 193, 63, 0, 126, 240, 92, 8, 51, 157, 240, 247, 136, 127, 60, 73,
+ 156, 248, 72, 24, 51, 176, 29, 30, 3, 30, 19, 53, 248, 71, 250,
+ 97, 134, 172, 39, 154, 19, 50, 226, 21, 0, 251, 172, 28, 249, 67,
+ 253, 48, 67, 214, 19, 33, 95, 92, 131, 7, 239, 142, 116, 241, 124,
+ 168, 31, 102, 200, 122, 34, 228, 75, 98, 6, 202, 84, 198, 151, 7,
+ 250, 97, 6, 213, 19, 93, 88, 187, 227, 179, 0, 167, 171, 159, 220,
+ 248, 34, 243, 143, 122, 34, 165, 216, 45, 173, 242, 228, 150, 78, 227,
+ 2, 180, 49, 226, 231, 35, 175, 126, 242, 65, 163, 15, 206, 101, 235,
+ 77, 230, 128, 223, 13, 105, 172, 78, 252, 60, 9, 126, 242, 206, 53,
+ 78, 166, 54, 116, 254, 163, 30, 161, 120, 189, 91, 26, 223, 164, 110,
+ 182, 78, 53, 248, 7, 4, 191, 83, 213, 79, 54, 158, 59, 239, 143,
+ 249, 170, 29, 220, 151, 97, 163, 219, 158, 49, 136, 19, 132, 25, 197,
+ 61, 64, 63, 17, 194, 140, 35, 87, 31, 190, 15, 230, 63, 249, 58,
+ 212, 224, 239, 19, 181, 235, 251, 92, 251, 214, 148, 167, 142, 152, 169,
+ 165, 209, 15, 58, 186, 72, 156, 112, 237, 154, 144, 161, 0, 239, 164,
+ 96, 229, 180, 46, 234, 171, 35, 102, 52, 203, 56, 229, 242, 245, 56,
+ 214, 35, 159, 208, 3, 208, 72, 151, 214, 241, 131, 116, 196, 140, 102,
+ 25, 207, 95, 62, 116, 198, 122, 228, 151, 169, 193, 179, 246, 109, 77,
+ 245, 211, 17, 51, 154, 101, 140, 250, 165, 26, 103, 186, 154, 170, 236,
+ 110, 173, 108, 41, 18, 69, 180, 105, 39, 135, 118, 68, 62, 132, 232,
+ 110, 41, 49, 20, 247, 92, 115, 220, 13, 28, 88, 66, 221, 173, 214,
+ 10, 239, 237, 182, 237, 227, 164, 164, 187, 79, 243, 167, 175, 247, 31,
+ 200, 187, 79, 250, 205, 146, 205, 52, 135, 213, 36, 92, 239, 55, 141,
+ 72, 166, 249, 176, 170, 172, 151, 68, 237, 167, 155, 95, 42, 102, 219,
+ 164, 208, 41, 79, 191, 41, 105, 113, 68, 26, 221, 237, 215, 103, 23,
+ 254, 26, 217, 97, 122, 162, 59, 90, 91, 200, 160, 223, 88, 30, 97,
+ 235, 147, 199, 233, 126, 175, 55, 243, 246, 45, 142, 202, 162, 205, 62,
+ 141, 99, 219, 200, 233, 95, 238, 110, 74, 250, 87, 248, 105, 58, 112,
+ 179, 165, 192, 59, 159, 163, 19, 186, 84, 98, 219, 92, 164, 93, 102,
+ 154, 176, 114, 47, 211, 167, 39, 148, 58, 243, 215, 254, 175, 209, 255,
+ 171, 86, 153, 237, 155, 67, 203, 220, 234, 179, 182, 186, 73, 247, 14,
+ 225, 31, 187, 197, 209, 185, 180, 111, 52, 197, 182, 201, 163, 47, 84,
+ 154, 175, 164, 171, 71, 220, 163, 151, 93, 220, 44, 176, 230, 240, 128,
+ 62, 251, 24, 173, 147, 40, 104, 179, 1, 166, 174, 42, 125, 159, 208,
+ 13, 108, 234, 243, 126, 223, 111, 81, 5, 180, 223, 227, 78, 108, 155,
+ 151, 244, 149, 10, 61, 149, 244, 207, 240, 66, 250, 65, 27, 111, 87,
+ 126, 59, 191, 165, 27, 87, 25, 199, 182, 41, 162, 229, 19, 3, 85,
+ 116, 196, 71, 122, 224, 133, 105, 174, 252, 53, 158, 47, 244, 222, 239,
+ 51, 217, 54, 223, 233, 27, 86, 51, 92, 85, 245, 176, 98, 250, 155,
+ 83, 168, 43, 255, 55, 42, 165, 71, 248, 142, 71, 109, 152, 143, 139,
+ 84, 239, 96, 36, 53, 98, 150, 30, 240, 227, 237, 43, 58, 101, 204,
+ 92, 104, 141, 222, 205, 148, 233, 246, 45, 72, 73, 87, 144, 86, 96,
+ 18, 206, 249, 243, 246, 253, 45, 175, 200, 48, 174, 3, 216, 54, 149,
+ 24, 231, 3, 82, 21, 45, 173, 204, 56, 55, 177, 231, 215, 87, 94,
+ 133, 217, 145, 208, 132, 109, 83, 141, 217, 209, 183, 142, 146, 254, 29,
+ 94, 157, 201, 61, 40, 18, 176, 85, 77, 134, 91, 103, 179, 192, 116,
+ 198, 167, 186, 140, 208, 250, 27, 142, 37, 32, 190, 162, 88, 50, 15,
+ 196, 18, 24, 47, 81, 44, 65, 52, 60, 231, 192, 61, 215, 204, 111,
+ 17, 136, 37, 5, 171, 37, 89, 40, 150, 44, 200, 87, 213, 132, 103,
+ 130, 88, 18, 179, 176, 22, 111, 29, 184, 20, 196, 18, 110, 156, 78,
+ 194, 107, 65, 70, 32, 150, 240, 141, 211, 42, 27, 236, 167, 15, 78,
+ 138, 195, 177, 100, 141, 245, 90, 22, 151, 105, 116, 216, 99, 254, 53,
+ 57, 99, 16, 75, 70, 108, 221, 129, 99, 73, 163, 135, 241, 74, 186,
+ 10, 136, 37, 53, 157, 35, 120, 251, 126, 1, 177, 36, 229, 59, 122,
+ 103, 57, 109, 26, 36, 119, 86, 189, 243, 105, 90, 242, 112, 37, 111,
+ 60, 48, 137, 62, 71, 43, 198, 63, 117, 70, 177, 196, 43, 181, 169,
+ 82, 86, 101, 16, 75, 154, 164, 254, 37, 16, 255, 174, 209, 211, 70,
+ 39, 224, 88, 146, 185, 41, 155, 181, 213, 77, 186, 81, 222, 83, 222,
+ 190, 159, 162, 114, 233, 236, 122, 53, 92, 81, 44, 89, 185, 161, 30,
+ 27, 15, 238, 209, 109, 235, 73, 4, 124, 237, 1, 45, 94, 83, 215,
+ 21, 197, 146, 228, 11, 42, 218, 56, 226, 9, 221, 191, 164, 46, 63,
+ 62, 64, 44, 169, 224, 89, 31, 199, 18, 119, 214, 223, 77, 34, 10,
+ 233, 101, 79, 90, 8, 96, 250, 45, 109, 92, 161, 35, 142, 37, 67,
+ 171, 117, 98, 251, 126, 164, 247, 213, 118, 20, 144, 251, 133, 78, 29,
+ 106, 131, 99, 73, 82, 159, 22, 236, 59, 23, 211, 155, 93, 27, 9,
+ 198, 18, 145, 71, 77, 28, 75, 188, 3, 171, 170, 250, 130, 88, 242,
+ 239, 138, 10, 188, 125, 171, 128, 88, 98, 126, 161, 42, 142, 37, 190,
+ 193, 111, 148, 223, 165, 22, 136, 37, 121, 238, 167, 120, 191, 209, 75,
+ 16, 75, 222, 236, 184, 225, 140, 98, 201, 137, 109, 3, 148, 244, 47,
+ 183, 202, 76, 242, 246, 236, 12, 222, 119, 6, 177, 100, 141, 236, 167,
+ 51, 138, 37, 77, 150, 54, 114, 65, 177, 68, 212, 104, 180, 139, 80,
+ 44, 225, 214, 96, 45, 48, 13, 99, 137, 208, 218, 44, 142, 37, 32,
+ 143, 66, 177, 228, 75, 171, 118, 114, 152, 23, 161, 88, 130, 232, 217,
+ 7, 99, 40, 238, 185, 102, 126, 123, 61, 74, 168, 167, 139, 209, 90,
+ 153, 29, 253, 120, 244, 56, 37, 61, 106, 170, 63, 125, 169, 229, 2,
+ 222, 117, 176, 62, 177, 155, 105, 46, 71, 79, 194, 235, 132, 217, 32,
+ 150, 240, 229, 232, 74, 61, 22, 238, 167, 195, 61, 235, 100, 163, 88,
+ 50, 112, 84, 129, 50, 110, 117, 137, 73, 163, 207, 183, 221, 198, 27,
+ 195, 146, 34, 14, 211, 45, 169, 9, 56, 150, 220, 91, 31, 160, 252,
+ 254, 203, 231, 30, 167, 71, 25, 95, 230, 245, 151, 170, 178, 44, 250,
+ 91, 190, 137, 27, 138, 37, 139, 43, 152, 43, 233, 53, 32, 47, 137,
+ 108, 222, 144, 119, 63, 92, 11, 16, 75, 78, 191, 169, 227, 134, 98,
+ 137, 115, 70, 53, 37, 61, 31, 196, 18, 191, 40, 19, 254, 125, 230,
+ 32, 150, 52, 114, 188, 231, 138, 98, 137, 34, 240, 136, 146, 158, 0,
+ 98, 201, 177, 13, 171, 249, 207, 201, 197, 228, 210, 86, 117, 135, 224,
+ 88, 242, 248, 199, 89, 165, 238, 9, 145, 247, 232, 17, 85, 87, 156,
+ 224, 235, 107, 25, 253, 128, 14, 25, 224, 147, 133, 98, 73, 231, 159,
+ 199, 149, 244, 106, 144, 151, 172, 120, 98, 204, 251, 141, 254, 149, 21,
+ 208, 141, 188, 28, 178, 81, 44, 25, 253, 122, 128, 146, 126, 54, 191,
+ 144, 14, 241, 15, 226, 237, 27, 12, 98, 201, 67, 183, 168, 108, 20,
+ 75, 134, 236, 90, 162, 164, 183, 135, 127, 164, 55, 87, 92, 205, 219,
+ 119, 61, 136, 37, 109, 159, 111, 202, 70, 177, 228, 116, 151, 45, 74,
+ 250, 83, 120, 49, 253, 102, 241, 54, 222, 190, 37, 32, 150, 88, 120,
+ 110, 70, 109, 152, 202, 225, 9, 217, 40, 47, 17, 37, 111, 200, 230,
+ 199, 180, 49, 99, 210, 110, 93, 54, 138, 37, 69, 215, 214, 40, 105,
+ 83, 16, 75, 238, 79, 229, 127, 231, 122, 167, 42, 50, 197, 118, 107,
+ 178, 81, 44, 249, 217, 60, 78, 73, 119, 0, 121, 137, 85, 221, 101,
+ 252, 235, 216, 167, 170, 48, 51, 174, 200, 178, 81, 44, 25, 247, 51,
+ 84, 73, 127, 0, 177, 196, 241, 172, 119, 182, 80, 44, 225, 214, 231,
+ 45, 48, 125, 2, 196, 18, 161, 117, 123, 110, 142, 211, 15, 199, 146,
+ 37, 32, 47, 129, 243, 31, 20, 75, 16, 237, 10, 242, 18, 238, 185,
+ 102, 126, 59, 64, 94, 210, 242, 197, 28, 124, 254, 210, 172, 149, 138,
+ 166, 65, 94, 226, 226, 61, 155, 183, 239, 71, 144, 151, 112, 243, 243,
+ 36, 188, 134, 108, 2, 98, 9, 223, 252, 92, 53, 246, 236, 167, 223,
+ 159, 70, 109, 82, 232, 99, 78, 17, 82, 148, 151, 196, 164, 241, 159,
+ 251, 44, 141, 58, 76, 239, 216, 133, 244, 202, 160, 247, 207, 87, 209,
+ 98, 144, 151, 100, 120, 241, 235, 11, 231, 56, 77, 175, 33, 185, 114,
+ 250, 235, 20, 150, 6, 121, 201, 85, 115, 161, 119, 62, 71, 103, 122,
+ 160, 54, 23, 233, 39, 203, 195, 89, 125, 47, 211, 149, 111, 10, 173,
+ 39, 95, 163, 227, 99, 145, 94, 57, 244, 165, 231, 104, 61, 249, 38,
+ 109, 228, 33, 180, 174, 155, 75, 175, 57, 134, 218, 228, 209, 190, 25,
+ 42, 218, 20, 204, 113, 58, 28, 229, 239, 43, 6, 177, 36, 42, 10,
+ 181, 81, 208, 127, 109, 83, 201, 53, 7, 121, 137, 85, 22, 255, 59,
+ 139, 162, 11, 232, 204, 157, 232, 251, 190, 164, 143, 119, 81, 173, 189,
+ 255, 6, 115, 156, 140, 43, 252, 190, 241, 3, 196, 146, 101, 230, 97,
+ 82, 20, 75, 196, 79, 102, 74, 85, 243, 163, 143, 244, 226, 67, 51,
+ 164, 252, 185, 227, 23, 122, 116, 143, 233, 82, 20, 75, 94, 190, 15,
+ 101, 109, 85, 76, 207, 216, 28, 42, 96, 171, 82, 186, 213, 8, 212,
+ 87, 196, 20, 236, 86, 209, 48, 150, 236, 252, 50, 157, 255, 251, 130,
+ 88, 18, 217, 103, 6, 62, 19, 188, 110, 217, 12, 182, 111, 5, 102,
+ 239, 85, 254, 119, 54, 2, 177, 196, 247, 17, 106, 83, 137, 217, 22,
+ 169, 210, 215, 20, 196, 18, 69, 19, 254, 59, 1, 225, 28, 39, 126,
+ 59, 178, 85, 53, 230, 47, 153, 202, 182, 191, 64, 44, 185, 238, 58,
+ 87, 42, 20, 75, 184, 189, 27, 22, 152, 62, 6, 98, 137, 208, 158,
+ 14, 84, 35, 83, 214, 197, 80, 173, 244, 246, 36, 177, 207, 3, 161,
+ 26, 89, 23, 92, 127, 241, 1, 125, 21, 121, 194, 53, 50, 216, 14,
+ 215, 175, 238, 114, 237, 67, 242, 12, 183, 22, 3, 249, 226, 250, 21,
+ 160, 161, 76, 21, 100, 12, 183, 22, 227, 67, 200, 128, 122, 35, 93,
+ 226, 239, 24, 110, 45, 6, 242, 37, 107, 100, 62, 172, 12, 201, 29,
+ 195, 173, 197, 64, 187, 27, 114, 253, 82, 148, 103, 216, 245, 75, 104,
+ 79, 67, 174, 95, 74, 238, 24, 118, 253, 18, 226, 4, 175, 197, 220,
+ 4, 126, 112, 79, 8, 51, 93, 185, 189, 250, 160, 111, 226, 45, 29,
+ 206, 67, 220, 38, 214, 48, 114, 137, 181, 152, 91, 134, 195, 12, 228,
+ 139, 207, 67, 0, 26, 202, 84, 142, 140, 255, 25, 14, 51, 18, 66,
+ 6, 212, 27, 233, 226, 249, 159, 225, 48, 3, 249, 170, 157, 135, 96,
+ 101, 40, 110, 26, 14, 51, 208, 238, 134, 92, 191, 132, 54, 54, 228,
+ 250, 165, 231, 127, 134, 93, 191, 132, 182, 51, 228, 250, 37, 196, 9,
+ 94, 139, 185, 6, 252, 224, 182, 16, 102, 186, 113, 235, 4, 55, 64,
+ 60, 207, 209, 97, 45, 230, 6, 49, 6, 220, 224, 218, 167, 92, 215,
+ 15, 51, 205, 158, 85, 227, 206, 17, 16, 50, 20, 224, 157, 20, 172,
+ 28, 234, 186, 126, 152, 249, 57, 32, 60, 11, 235, 145, 67, 232, 1,
+ 104, 164, 75, 206, 255, 244, 195, 204, 218, 199, 5, 220, 157, 23, 57,
+ 101, 214, 98, 88, 251, 250, 252, 79, 63, 204, 4, 206, 242, 229, 238,
+ 19, 188, 174, 253, 76, 13, 180, 41, 162, 181, 201, 249, 99, 95, 11,
+ 15, 63, 104, 191, 242, 242, 131, 246, 212, 198, 15, 218, 170, 188, 252,
+ 124, 120, 248, 65, 187, 232, 202, 15, 231, 102, 215, 136, 220, 236, 18,
+ 240, 131, 155, 2, 152, 177, 183, 227, 242, 6, 208, 87, 113, 69, 135,
+ 220, 236, 26, 225, 207, 87, 137, 220, 236, 138, 1, 115, 179, 171, 132,
+ 63, 3, 26, 202, 84, 54, 186, 98, 192, 220, 140, 144, 1, 245, 70,
+ 186, 196, 95, 54, 96, 110, 118, 165, 76, 110, 198, 202, 144, 92, 54,
+ 96, 110, 118, 197, 176, 227, 140, 232, 138, 97, 199, 25, 104, 79, 67,
+ 142, 51, 146, 203, 134, 29, 103, 32, 78, 112, 110, 118, 14, 248, 193,
+ 53, 33, 204, 112, 123, 152, 37, 160, 111, 226, 5, 29, 114, 179, 75,
+ 68, 78, 115, 145, 200, 205, 46, 24, 48, 55, 187, 72, 228, 102, 128,
+ 134, 50, 149, 185, 217, 121, 3, 230, 102, 132, 12, 168, 55, 210, 197,
+ 243, 188, 1, 115, 179, 11, 101, 114, 51, 86, 134, 226, 156, 1, 115,
+ 179, 11, 134, 157, 207, 64, 27, 27, 114, 62, 227, 121, 222, 176, 243,
+ 25, 104, 59, 67, 206, 103, 32, 78, 240, 89, 213, 163, 192, 15, 46,
+ 105, 199, 76, 232, 164, 0, 209, 12, 50, 111, 56, 11, 226, 249, 153,
+ 73, 98, 127, 255, 150, 114, 127, 255, 102, 204, 137, 248, 5, 217, 157,
+ 123, 198, 75, 255, 200, 205, 206, 18, 99, 192, 89, 226, 78, 4, 185,
+ 38, 63, 128, 99, 100, 17, 221, 115, 232, 211, 172, 150, 243, 166, 56,
+ 171, 48, 83, 69, 163, 31, 164, 140, 59, 142, 125, 205, 135, 144, 161,
+ 0, 239, 164, 96, 229, 196, 103, 105, 151, 177, 125, 118, 167, 236, 236,
+ 226, 66, 103, 21, 102, 52, 203, 184, 107, 245, 15, 55, 6, 156, 33,
+ 244, 0, 52, 214, 229, 132, 118, 25, 199, 99, 26, 158, 220, 22, 33,
+ 118, 83, 97, 70, 179, 140, 191, 159, 53, 224, 114, 204, 51, 101, 114,
+ 179, 51, 236, 190, 210, 12, 237, 50, 234, 45, 235, 37, 125, 103, 19,
+ 43, 85, 97, 70, 179, 140, 25, 5, 170, 189, 101, 195, 140, 85, 118,
+ 183, 86, 182, 84, 157, 13, 130, 118, 68, 252, 16, 13, 207, 6, 113,
+ 207, 69, 162, 53, 162, 230, 162, 221, 162, 22, 162, 84, 240, 135, 239,
+ 114, 28, 208, 141, 113, 112, 221, 194, 182, 233, 199, 160, 246, 166, 89,
+ 3, 25, 187, 174, 114, 222, 49, 224, 55, 227, 197, 220, 105, 115, 147,
+ 109, 51, 140, 121, 57, 44, 91, 73, 91, 101, 141, 100, 230, 45, 74,
+ 230, 237, 107, 220, 221, 135, 233, 99, 126, 136, 109, 51, 158, 89, 53,
+ 49, 93, 73, 87, 44, 157, 200, 252, 232, 120, 132, 183, 111, 123, 211,
+ 169, 76, 223, 160, 189, 108, 155, 25, 76, 97, 229, 68, 37, 93, 224,
+ 54, 147, 57, 106, 191, 133, 183, 111, 177, 124, 22, 211, 163, 194, 70,
+ 182, 205, 108, 230, 199, 134, 117, 42, 90, 58, 135, 57, 214, 118, 13,
+ 191, 190, 242, 185, 204, 193, 51, 171, 216, 54, 243, 25, 187, 247, 241,
+ 153, 170, 186, 183, 140, 113, 220, 178, 130, 191, 111, 84, 12, 115, 160,
+ 46, 234, 27, 203, 220, 159, 181, 56, 83, 85, 159, 92, 196, 124, 106,
+ 185, 64, 64, 238, 98, 230, 68, 220, 84, 182, 205, 82, 198, 44, 200,
+ 143, 237, 187, 140, 25, 235, 238, 45, 208, 119, 57, 227, 230, 219, 19,
+ 159, 67, 67, 244, 253, 57, 113, 196, 115, 237, 99, 60, 244, 53, 136,
+ 63, 210, 215, 32, 158, 144, 175, 33, 26, 250, 26, 247, 28, 250, 90,
+ 83, 214, 215, 90, 98, 126, 239, 128, 175, 141, 176, 90, 133, 125, 13,
+ 181, 135, 190, 246, 209, 106, 143, 160, 175, 73, 173, 210, 177, 175, 73,
+ 126, 108, 193, 190, 22, 154, 183, 72, 208, 215, 114, 125, 226, 176, 175,
+ 237, 90, 185, 90, 73, 139, 129, 175, 109, 186, 186, 94, 208, 215, 134,
+ 164, 175, 198, 190, 102, 50, 51, 30, 251, 154, 99, 65, 156, 160, 175,
+ 13, 154, 18, 135, 125, 237, 139, 91, 28, 246, 181, 132, 26, 113, 130,
+ 190, 70, 21, 175, 196, 190, 182, 172, 69, 28, 246, 181, 195, 215, 248,
+ 251, 194, 115, 104, 67, 71, 174, 197, 190, 86, 177, 247, 42, 236, 107,
+ 15, 78, 198, 9, 250, 218, 138, 244, 37, 216, 215, 230, 251, 199, 98,
+ 95, 11, 178, 140, 17, 244, 181, 37, 142, 225, 216, 215, 16, 13, 125,
+ 141, 123, 206, 239, 107, 48, 14, 147, 190, 6, 227, 42, 242, 53, 68,
+ 187, 3, 95, 227, 158, 67, 95, 171, 9, 124, 205, 10, 248, 90, 35,
+ 204, 175, 0, 248, 218, 189, 31, 245, 241, 25, 89, 212, 190, 2, 240,
+ 181, 248, 218, 252, 235, 116, 166, 221, 189, 152, 121, 63, 26, 225, 51,
+ 178, 77, 71, 171, 126, 111, 9, 250, 218, 90, 185, 57, 111, 95, 19,
+ 224, 107, 223, 60, 43, 225, 51, 178, 118, 115, 69, 217, 200, 215, 54,
+ 86, 122, 195, 187, 206, 110, 11, 124, 173, 192, 228, 10, 62, 231, 26,
+ 36, 75, 201, 66, 190, 246, 248, 209, 158, 44, 33, 95, 235, 119, 107,
+ 123, 22, 242, 181, 37, 39, 55, 101, 33, 95, 123, 153, 188, 134, 183,
+ 239, 79, 224, 107, 233, 253, 22, 225, 51, 178, 225, 221, 99, 149, 116,
+ 5, 224, 107, 73, 141, 163, 179, 132, 124, 173, 114, 149, 227, 248, 140,
+ 108, 154, 245, 126, 37, 93, 5, 248, 218, 208, 67, 255, 242, 247, 5,
+ 190, 246, 176, 150, 44, 11, 249, 90, 223, 51, 67, 178, 84, 251, 65,
+ 150, 49, 238, 190, 237, 179, 4, 125, 205, 242, 5, 231, 107, 44, 253,
+ 0, 250, 26, 126, 206, 239, 107, 112, 60, 38, 125, 13, 142, 175, 200,
+ 215, 16, 13, 227, 26, 247, 28, 250, 218, 76, 224, 107, 179, 128, 175,
+ 133, 169, 197, 181, 89, 21, 230, 227, 243, 181, 168, 61, 140, 107, 84,
+ 45, 129, 181, 69, 16, 215, 146, 163, 195, 241, 249, 218, 251, 53, 85,
+ 116, 125, 224, 107, 213, 182, 243, 175, 1, 193, 184, 22, 24, 26, 142,
+ 207, 215, 46, 121, 164, 162, 127, 151, 76, 100, 172, 167, 241, 175, 195,
+ 218, 192, 49, 52, 133, 59, 35, 235, 251, 69, 69, 67, 95, 251, 183,
+ 162, 192, 58, 44, 240, 181, 27, 141, 80, 155, 217, 204, 206, 14, 44,
+ 13, 124, 109, 6, 29, 41, 21, 138, 107, 123, 70, 113, 231, 107, 15,
+ 143, 65, 103, 100, 101, 204, 115, 255, 72, 193, 243, 181, 175, 158, 70,
+ 224, 243, 181, 207, 140, 216, 179, 185, 192, 215, 30, 155, 11, 201, 93,
+ 204, 140, 11, 65, 109, 150, 50, 167, 214, 163, 190, 203, 152, 38, 89,
+ 66, 125, 151, 51, 94, 119, 185, 179, 185, 136, 134, 113, 141, 123, 206,
+ 63, 175, 133, 121, 57, 202, 209, 83, 14, 129, 188, 243, 28, 111, 142,
+ 174, 126, 54, 23, 244, 45, 58, 44, 156, 163, 195, 118, 248, 108, 238,
+ 17, 142, 191, 236, 176, 174, 57, 186, 230, 185, 26, 204, 19, 240, 217,
+ 220, 35, 196, 111, 24, 1, 26, 202, 84, 174, 73, 31, 214, 53, 71,
+ 215, 44, 3, 142, 15, 88, 15, 66, 6, 212, 27, 233, 146, 152, 174,
+ 107, 142, 174, 69, 6, 136, 11, 88, 143, 195, 101, 126, 195, 136, 149,
+ 97, 151, 174, 107, 142, 174, 89, 6, 244, 7, 124, 246, 245, 176, 250,
+ 89, 85, 46, 223, 146, 73, 17, 253, 163, 123, 38, 197, 151, 135, 169,
+ 157, 125, 45, 195, 143, 27, 83, 101, 82, 68, 67, 126, 124, 99, 173,
+ 218, 221, 129, 233, 101, 248, 225, 184, 9, 248, 177, 180, 146, 31, 79,
+ 60, 85, 187, 59, 176, 12, 63, 14, 27, 50, 41, 162, 33, 63, 62,
+ 204, 144, 243, 90, 136, 19, 124, 207, 182, 93, 160, 184, 232, 168, 16,
+ 102, 184, 179, 185, 118, 160, 111, 74, 170, 48, 102, 96, 59, 228, 7,
+ 41, 105, 28, 127, 42, 213, 112, 152, 129, 124, 241, 239, 36, 1, 26,
+ 202, 84, 206, 157, 83, 12, 135, 25, 59, 66, 6, 212, 27, 233, 226,
+ 147, 98, 56, 204, 64, 190, 36, 102, 236, 88, 25, 148, 125, 160, 193,
+ 48, 3, 237, 142, 107, 35, 191, 229, 110, 154, 48, 35, 10, 123, 40,
+ 213, 21, 51, 208, 198, 36, 63, 77, 152, 129, 252, 116, 197, 140, 15,
+ 201, 239, 23, 224, 167, 1, 51, 242, 89, 15, 165, 186, 98, 6, 218,
+ 142, 124, 63, 77, 152, 129, 239, 167, 43, 102, 32, 78, 112, 253, 212,
+ 37, 80, 156, 114, 72, 8, 51, 220, 217, 92, 10, 244, 77, 116, 11,
+ 20, 196, 12, 108, 135, 235, 142, 82, 238, 219, 219, 185, 5, 26, 12,
+ 51, 144, 47, 174, 159, 2, 26, 202, 84, 218, 214, 53, 208, 96, 152,
+ 145, 16, 50, 160, 222, 72, 23, 79, 30, 25, 229, 197, 12, 228, 171,
+ 86, 63, 101, 101, 40, 92, 12, 135, 25, 104, 119, 125, 49, 163, 182,
+ 182, 237, 26, 168, 55, 102, 212, 214, 182, 73, 126, 255, 71, 204, 168,
+ 173, 109, 187, 232, 143, 25, 181, 181, 109, 23, 14, 51, 146, 174, 129,
+ 98, 185, 93, 160, 0, 102, 184, 179, 185, 10, 231, 64, 177, 143, 147,
+ 48, 102, 96, 59, 92, 119, 116, 230, 248, 23, 117, 211, 15, 51, 106,
+ 245, 83, 66, 134, 2, 188, 147, 130, 149, 35, 235, 166, 31, 102, 212,
+ 234, 167, 78, 132, 30, 128, 70, 186, 152, 119, 211, 15, 51, 106, 245,
+ 83, 39, 117, 204, 64, 153, 202, 252, 175, 171, 126, 152, 65, 245, 83,
+ 23, 214, 238, 248, 142, 85, 121, 245, 147, 179, 254, 125, 243, 71, 253,
+ 20, 158, 165, 245, 30, 146, 162, 181, 126, 170, 118, 207, 9, 193, 79,
+ 113, 162, 250, 201, 13, 253, 236, 179, 202, 214, 200, 226, 31, 237, 150,
+ 182, 9, 136, 208, 90, 35, 83, 203, 245, 8, 126, 146, 46, 53, 78,
+ 42, 6, 121, 254, 81, 7, 41, 122, 189, 91, 218, 122, 98, 77, 173,
+ 117, 16, 181, 92, 175, 43, 193, 239, 116, 245, 147, 141, 183, 207, 253,
+ 99, 174, 11, 207, 230, 46, 28, 30, 174, 117, 174, 75, 142, 51, 16,
+ 39, 120, 109, 219, 17, 248, 129, 139, 16, 102, 184, 179, 185, 137, 93,
+ 2, 197, 146, 206, 194, 152, 129, 237, 240, 24, 208, 133, 227, 223, 58,
+ 113, 128, 142, 152, 209, 124, 222, 244, 183, 243, 66, 124, 54, 87, 66,
+ 200, 72, 4, 239, 148, 200, 202, 105, 29, 50, 80, 71, 204, 104, 150,
+ 177, 161, 168, 176, 27, 214, 163, 51, 161, 7, 160, 145, 46, 173, 115,
+ 70, 235, 136, 25, 205, 50, 162, 198, 191, 194, 103, 115, 37, 157, 213,
+ 49, 3, 101, 194, 127, 147, 126, 14, 208, 17, 51, 154, 101, 244, 35,
+ 207, 230, 2, 187, 163, 125, 235, 129, 109, 218, 201, 161, 29, 17, 63,
+ 68, 119, 74, 137, 161, 184, 231, 224, 255, 84, 3, 253, 128, 127, 59,
+ 19, 117, 224, 102, 3, 75, 168, 169, 109, 70, 225, 243, 116, 45, 215,
+ 132, 42, 105, 239, 105, 254, 180, 120, 209, 66, 92, 247, 25, 12, 240,
+ 17, 0, 254, 230, 137, 36, 92, 173, 106, 201, 102, 154, 195, 106, 18,
+ 94, 223, 128, 231, 233, 248, 176, 42, 98, 207, 211, 5, 53, 69, 117,
+ 230, 20, 218, 102, 122, 34, 91, 83, 77, 163, 11, 207, 110, 16, 168,
+ 169, 30, 166, 87, 180, 66, 117, 209, 12, 154, 154, 19, 195, 202, 61,
+ 78, 23, 174, 155, 39, 208, 55, 139, 78, 79, 69, 99, 165, 156, 238,
+ 190, 46, 140, 149, 123, 154, 190, 57, 123, 154, 192, 186, 193, 57, 250,
+ 99, 189, 137, 108, 155, 139, 116, 161, 253, 48, 182, 239, 101, 58, 191,
+ 111, 47, 1, 185, 215, 232, 169, 118, 150, 108, 155, 28, 122, 120, 108,
+ 11, 213, 26, 75, 196, 77, 122, 248, 125, 59, 129, 190, 185, 244, 240,
+ 108, 20, 171, 242, 104, 171, 76, 118, 109, 36, 226, 30, 253, 205, 50,
+ 73, 224, 157, 31, 208, 135, 211, 142, 177, 109, 20, 244, 148, 227, 215,
+ 84, 117, 254, 136, 39, 116, 207, 211, 143, 121, 251, 138, 163, 11, 232,
+ 186, 235, 191, 179, 109, 94, 210, 245, 236, 170, 43, 253, 161, 114, 68,
+ 33, 189, 177, 142, 132, 183, 38, 248, 46, 234, 45, 237, 188, 212, 131,
+ 109, 83, 68, 79, 179, 31, 164, 164, 75, 194, 63, 210, 30, 121, 163,
+ 4, 234, 152, 95, 232, 9, 145, 131, 217, 54, 223, 233, 110, 212, 0,
+ 246, 174, 191, 98, 186, 154, 81, 111, 254, 51, 158, 81, 165, 180, 123,
+ 39, 23, 212, 134, 153, 254, 165, 91, 150, 170, 182, 100, 196, 108, 63,
+ 210, 133, 183, 175, 209, 41, 99, 166, 141, 87, 119, 182, 141, 41, 147,
+ 191, 206, 89, 85, 123, 149, 86, 96, 2, 238, 116, 20, 168, 219, 86,
+ 100, 46, 78, 170, 205, 182, 169, 196, 60, 247, 170, 162, 164, 127, 187,
+ 85, 102, 236, 41, 35, 129, 250, 105, 21, 102, 143, 83, 37, 182, 77,
+ 53, 166, 117, 134, 169, 146, 54, 137, 168, 206, 244, 244, 255, 41, 240,
+ 125, 107, 50, 220, 186, 162, 5, 166, 225, 121, 58, 114, 189, 81, 100,
+ 212, 66, 84, 29, 252, 53, 54, 106, 241, 231, 25, 24, 16, 95, 81,
+ 44, 105, 213, 186, 157, 28, 198, 75, 20, 75, 16, 253, 241, 96, 12,
+ 197, 61, 215, 28, 75, 118, 245, 41, 161, 238, 157, 104, 129, 207, 211,
+ 85, 17, 181, 87, 210, 57, 161, 254, 180, 155, 184, 115, 54, 23, 75,
+ 44, 65, 44, 177, 4, 177, 164, 30, 238, 219, 116, 233, 102, 154, 27,
+ 167, 147, 240, 250, 213, 143, 240, 100, 154, 111, 156, 22, 41, 207, 61,
+ 237, 167, 47, 247, 240, 192, 177, 228, 91, 211, 186, 44, 62, 210, 232,
+ 247, 191, 46, 241, 158, 17, 251, 9, 207, 192, 12, 148, 156, 64, 177,
+ 36, 211, 207, 77, 117, 254, 24, 196, 146, 131, 78, 209, 78, 66, 177,
+ 100, 244, 145, 67, 78, 40, 150, 180, 126, 248, 203, 9, 197, 146, 207,
+ 198, 214, 206, 66, 177, 36, 181, 133, 11, 62, 155, 187, 244, 104, 176,
+ 179, 234, 155, 95, 166, 123, 252, 195, 127, 174, 183, 66, 244, 53, 218,
+ 163, 205, 38, 103, 20, 75, 172, 188, 127, 43, 233, 106, 32, 150, 92,
+ 163, 29, 4, 238, 38, 200, 165, 7, 191, 62, 132, 207, 249, 87, 141,
+ 221, 166, 164, 187, 129, 88, 210, 170, 201, 50, 222, 190, 133, 32, 150,
+ 140, 58, 127, 238, 24, 138, 37, 158, 221, 140, 149, 118, 126, 21, 254,
+ 132, 62, 231, 28, 193, 235, 167, 95, 163, 10, 104, 251, 210, 36, 28,
+ 75, 102, 39, 92, 85, 210, 165, 225, 133, 116, 113, 167, 34, 222, 190,
+ 223, 64, 44, 89, 183, 185, 26, 142, 37, 70, 209, 22, 42, 108, 129,
+ 88, 210, 127, 98, 67, 193, 88, 242, 81, 84, 31, 199, 146, 15, 149,
+ 234, 227, 88, 82, 100, 94, 159, 31, 151, 32, 150, 48, 243, 234, 225,
+ 88, 146, 118, 78, 117, 214, 220, 4, 196, 146, 86, 230, 252, 114, 225,
+ 217, 92, 197, 30, 59, 28, 75, 38, 246, 80, 181, 111, 8, 98, 201,
+ 146, 251, 98, 222, 190, 143, 65, 44, 185, 187, 98, 64, 38, 138, 37,
+ 15, 125, 45, 50, 85, 107, 49, 149, 153, 71, 97, 233, 252, 254, 12,
+ 98, 201, 8, 71, 52, 6, 86, 99, 218, 57, 170, 214, 24, 225, 25,
+ 152, 153, 147, 210, 4, 198, 153, 154, 12, 183, 110, 108, 129, 105, 24,
+ 75, 200, 245, 100, 222, 88, 2, 242, 40, 20, 75, 106, 128, 88, 2,
+ 243, 34, 20, 75, 16, 13, 207, 230, 114, 207, 53, 199, 146, 215, 30,
+ 37, 84, 77, 103, 55, 28, 75, 46, 231, 251, 42, 233, 246, 83, 253,
+ 233, 131, 62, 11, 136, 88, 82, 15, 196, 18, 11, 37, 15, 212, 215,
+ 35, 118, 51, 205, 229, 232, 73, 120, 125, 242, 36, 200, 75, 248, 114,
+ 116, 216, 119, 83, 244, 126, 218, 230, 191, 247, 89, 40, 150, 12, 126,
+ 41, 87, 210, 211, 64, 44, 185, 243, 106, 21, 239, 119, 243, 5, 177,
+ 228, 197, 139, 202, 89, 40, 150, 204, 127, 211, 67, 105, 179, 160, 240,
+ 227, 116, 251, 6, 141, 120, 177, 245, 0, 196, 146, 249, 177, 119, 241,
+ 157, 33, 189, 76, 108, 149, 103, 94, 95, 132, 159, 166, 29, 92, 167,
+ 242, 158, 145, 93, 2, 98, 9, 179, 229, 31, 87, 20, 75, 170, 139,
+ 142, 42, 233, 39, 225, 151, 233, 11, 99, 46, 242, 246, 157, 11, 98,
+ 73, 160, 199, 77, 124, 54, 183, 161, 60, 67, 73, 175, 142, 188, 73,
+ 223, 108, 190, 141, 183, 175, 83, 76, 46, 253, 189, 208, 6, 159, 205,
+ 109, 96, 45, 81, 190, 255, 29, 16, 75, 94, 45, 203, 224, 245, 181,
+ 69, 178, 7, 244, 86, 159, 191, 241, 217, 220, 58, 23, 238, 40, 233,
+ 55, 243, 159, 208, 225, 179, 43, 243, 174, 235, 230, 131, 188, 36, 217,
+ 200, 10, 159, 205, 173, 51, 85, 117, 135, 242, 79, 144, 151, 132, 126,
+ 248, 139, 183, 239, 151, 200, 183, 244, 237, 238, 11, 241, 217, 220, 54,
+ 39, 84, 103, 85, 175, 204, 255, 72, 63, 108, 177, 137, 183, 239, 49,
+ 16, 75, 94, 223, 77, 192, 103, 115, 135, 214, 85, 157, 181, 253, 21,
+ 94, 76, 111, 27, 244, 55, 255, 90, 116, 116, 41, 189, 214, 29, 183,
+ 97, 168, 223, 42, 89, 21, 65, 44, 121, 118, 52, 129, 255, 92, 175,
+ 220, 152, 185, 186, 149, 59, 155, 187, 251, 173, 234, 172, 173, 49, 136,
+ 37, 177, 46, 252, 103, 115, 45, 78, 85, 100, 82, 155, 114, 103, 115,
+ 63, 184, 169, 244, 109, 39, 173, 204, 4, 140, 228, 63, 155, 91, 253,
+ 84, 21, 166, 214, 142, 40, 124, 54, 247, 235, 137, 25, 74, 186, 24,
+ 196, 146, 237, 201, 67, 5, 207, 230, 114, 251, 2, 44, 48, 125, 28,
+ 196, 18, 114, 191, 128, 200, 200, 10, 196, 18, 43, 16, 75, 172, 254,
+ 136, 37, 112, 190, 132, 98, 73, 36, 152, 227, 244, 35, 206, 230, 34,
+ 218, 9, 204, 113, 250, 17, 103, 115, 85, 177, 36, 12, 196, 18, 110,
+ 77, 120, 38, 152, 227, 84, 242, 158, 133, 207, 230, 86, 157, 161, 58,
+ 83, 216, 27, 204, 113, 6, 68, 112, 231, 17, 7, 139, 102, 136, 224,
+ 142, 188, 121, 162, 233, 184, 239, 123, 120, 54, 23, 207, 207, 147, 240,
+ 250, 51, 60, 155, 203, 55, 63, 23, 177, 247, 15, 181, 234, 27, 129,
+ 207, 230, 58, 95, 99, 105, 16, 75, 6, 12, 140, 20, 60, 155, 219,
+ 241, 127, 220, 217, 220, 235, 31, 209, 221, 199, 199, 233, 195, 85, 101,
+ 2, 231, 107, 179, 104, 235, 55, 145, 248, 108, 110, 215, 44, 180, 174,
+ 123, 154, 238, 187, 82, 104, 93, 247, 28, 125, 207, 42, 18, 159, 205,
+ 61, 248, 9, 157, 175, 189, 76, 47, 184, 38, 240, 59, 178, 96, 142,
+ 227, 145, 205, 157, 205, 157, 251, 62, 130, 181, 213, 77, 122, 191, 68,
+ 72, 223, 92, 250, 84, 17, 119, 54, 247, 98, 1, 119, 54, 247, 250,
+ 61, 254, 190, 70, 209, 15, 232, 252, 134, 220, 217, 220, 49, 243, 35,
+ 216, 115, 204, 79, 232, 71, 249, 252, 107, 254, 181, 65, 44, 249, 215,
+ 45, 28, 159, 205, 237, 192, 254, 222, 109, 125, 16, 75, 254, 110, 207,
+ 127, 102, 244, 49, 200, 75, 102, 47, 155, 133, 207, 230, 158, 106, 175,
+ 242, 171, 183, 32, 47, 177, 206, 153, 46, 112, 174, 247, 11, 93, 119,
+ 23, 119, 54, 183, 235, 180, 233, 248, 108, 238, 8, 55, 129, 243, 181,
+ 32, 47, 177, 252, 139, 59, 155, 59, 113, 33, 119, 54, 55, 227, 152,
+ 240, 217, 220, 65, 125, 185, 179, 185, 94, 155, 185, 179, 185, 67, 94,
+ 11, 159, 205, 109, 90, 97, 38, 62, 155, 107, 177, 69, 69, 155, 128,
+ 88, 82, 217, 113, 150, 84, 104, 142, 179, 32, 142, 59, 155, 107, 28,
+ 48, 155, 61, 3, 93, 157, 249, 89, 71, 248, 108, 46, 183, 239, 195,
+ 2, 211, 48, 47, 33, 247, 131, 136, 140, 102, 129, 88, 50, 11, 196,
+ 146, 89, 127, 238, 101, 119, 228, 106, 100, 158, 17, 129, 98, 73, 87,
+ 161, 26, 25, 119, 54, 87, 2, 250, 38, 118, 20, 174, 145, 193, 118,
+ 184, 126, 213, 137, 88, 139, 233, 104, 192, 181, 152, 78, 68, 253, 10,
+ 208, 80, 166, 50, 186, 68, 26, 112, 45, 134, 144, 1, 245, 70, 186,
+ 80, 145, 6, 92, 139, 233, 88, 102, 45, 134, 149, 145, 19, 97, 192,
+ 181, 152, 142, 129, 6, 93, 191, 132, 54, 54, 228, 250, 37, 21, 25,
+ 104, 208, 245, 75, 104, 59, 67, 174, 95, 66, 156, 224, 187, 133, 231,
+ 2, 63, 112, 20, 194, 12, 119, 54, 55, 39, 60, 80, 236, 57, 95,
+ 24, 51, 176, 29, 190, 147, 55, 156, 227, 175, 152, 103, 56, 204, 120,
+ 18, 50, 114, 192, 59, 229, 176, 114, 66, 230, 25, 14, 51, 144, 47,
+ 214, 3, 208, 88, 151, 121, 134, 195, 140, 231, 124, 117, 204, 64, 153,
+ 202, 181, 140, 185, 134, 195, 12, 180, 187, 33, 215, 47, 67, 230, 25,
+ 118, 253, 82, 52, 207, 176, 235, 151, 208, 118, 134, 92, 191, 132, 56,
+ 65, 152, 201, 153, 9, 252, 32, 66, 8, 51, 220, 217, 220, 248, 57,
+ 160, 239, 108, 97, 204, 192, 118, 248, 110, 225, 57, 28, 255, 196, 48,
+ 253, 48, 227, 89, 235, 43, 119, 183, 48, 33, 35, 30, 188, 83, 60,
+ 43, 199, 46, 76, 63, 204, 132, 121, 158, 193, 247, 164, 66, 190, 88,
+ 15, 64, 35, 93, 228, 179, 244, 195, 140, 229, 198, 57, 248, 247, 253,
+ 204, 103, 171, 99, 6, 202, 84, 234, 58, 75, 63, 204, 68, 79, 228,
+ 48, 3, 237, 174, 237, 172, 42, 180, 41, 199, 91, 243, 127, 127, 236,
+ 221, 226, 225, 7, 237, 87, 94, 126, 208, 158, 218, 248, 65, 91, 149,
+ 151, 159, 39, 15, 63, 104, 23, 93, 249, 33, 204, 64, 156, 224, 223,
+ 74, 153, 6, 232, 185, 2, 152, 33, 206, 230, 122, 130, 190, 57, 211,
+ 133, 49, 3, 219, 225, 49, 96, 6, 199, 223, 103, 186, 225, 198, 25,
+ 200, 23, 143, 1, 128, 134, 50, 149, 51, 131, 80, 195, 141, 51, 158,
+ 132, 12, 168, 55, 210, 69, 22, 106, 184, 113, 6, 242, 85, 251, 173,
+ 20, 86, 134, 121, 168, 225, 198, 25, 104, 119, 67, 142, 51, 208, 198,
+ 134, 28, 103, 100, 161, 134, 29, 103, 204, 67, 13, 59, 206, 40, 113,
+ 130, 246, 56, 4, 3, 63, 152, 41, 132, 25, 110, 15, 179, 57, 232,
+ 43, 153, 42, 140, 25, 216, 14, 143, 1, 33, 28, 255, 148, 41, 134,
+ 195, 12, 228, 139, 231, 26, 224, 157, 160, 76, 229, 92, 99, 138, 225,
+ 48, 3, 249, 226, 57, 19, 160, 145, 46, 57, 147, 13, 135, 25, 201,
+ 212, 50, 107, 254, 83, 85, 188, 125, 38, 27, 14, 51, 208, 238, 134,
+ 156, 207, 80, 83, 12, 59, 159, 129, 246, 52, 228, 124, 198, 103, 178,
+ 97, 231, 51, 16, 39, 24, 51, 19, 128, 31, 76, 211, 132, 153, 80,
+ 223, 41, 147, 102, 78, 86, 110, 250, 39, 190, 135, 15, 232, 171, 8,
+ 12, 20, 190, 3, 34, 152, 216, 247, 21, 196, 181, 151, 79, 10, 212,
+ 241, 60, 187, 169, 70, 63, 24, 113, 230, 73, 10, 222, 247, 21, 68,
+ 236, 251, 2, 52, 148, 169, 244, 185, 137, 129, 58, 158, 103, 215, 44,
+ 227, 88, 250, 90, 123, 172, 7, 33, 3, 234, 141, 116, 145, 5, 4,
+ 234, 120, 158, 93, 179, 12, 215, 253, 215, 113, 110, 6, 249, 170, 221,
+ 1, 193, 202, 240, 241, 15, 212, 241, 60, 187, 102, 25, 182, 7, 84,
+ 191, 189, 92, 196, 218, 221, 90, 217, 82, 117, 174, 8, 218, 17, 249,
+ 16, 162, 67, 29, 151, 208, 220, 115, 205, 113, 87, 209, 170, 62, 35,
+ 251, 22, 197, 254, 182, 114, 63, 6, 181, 175, 248, 221, 155, 9, 110,
+ 145, 196, 219, 183, 88, 236, 199, 188, 92, 94, 133, 253, 61, 244, 96,
+ 166, 176, 175, 175, 146, 174, 252, 121, 46, 211, 249, 112, 42, 239, 239,
+ 164, 255, 92, 24, 203, 28, 95, 60, 211, 70, 245, 116, 37, 166, 219,
+ 228, 175, 39, 158, 107, 31, 123, 138, 88, 191, 32, 109, 0, 191, 51,
+ 178, 1, 162, 161, 13, 184, 231, 218, 109, 208, 100, 102, 91, 7, 100,
+ 3, 212, 30, 218, 192, 117, 209, 40, 123, 33, 27, 204, 60, 124, 56,
+ 5, 217, 32, 54, 171, 118, 42, 178, 193, 145, 154, 147, 82, 133, 108,
+ 112, 194, 164, 233, 62, 100, 3, 68, 67, 27, 112, 207, 249, 109, 0,
+ 253, 22, 217, 224, 59, 176, 1, 244, 67, 100, 3, 68, 223, 234, 180,
+ 132, 230, 158, 107, 230, 39, 105, 89, 159, 73, 173, 49, 197, 13, 217,
+ 0, 181, 247, 1, 54, 184, 94, 146, 192, 219, 119, 45, 176, 193, 186,
+ 51, 165, 153, 200, 6, 63, 7, 171, 246, 181, 124, 253, 52, 151, 249,
+ 154, 185, 131, 119, 109, 241, 43, 176, 129, 255, 29, 159, 12, 100, 3,
+ 68, 183, 4, 54, 224, 158, 243, 219, 0, 226, 138, 244, 3, 136, 19,
+ 100, 3, 68, 67, 63, 224, 158, 107, 247, 131, 2, 92, 87, 239, 199,
+ 160, 246, 74, 63, 200, 227, 239, 11, 253, 32, 44, 44, 18, 255, 150,
+ 228, 213, 125, 42, 26, 250, 193, 149, 18, 254, 220, 7, 250, 1, 55,
+ 175, 88, 137, 105, 232, 7, 34, 129, 223, 131, 196, 99, 192, 4, 98,
+ 175, 164, 47, 136, 107, 193, 188, 99, 128, 131, 218, 24, 0, 250, 42,
+ 198, 233, 48, 6, 76, 32, 98, 231, 120, 174, 125, 200, 184, 64, 189,
+ 238, 52, 137, 153, 180, 192, 14, 199, 206, 241, 196, 24, 0, 104, 40,
+ 83, 217, 104, 92, 160, 94, 119, 154, 76, 72, 110, 159, 138, 245, 32,
+ 100, 64, 189, 145, 46, 241, 126, 129, 122, 221, 105, 114, 126, 113, 40,
+ 119, 63, 215, 184, 50, 99, 0, 43, 67, 226, 23, 168, 215, 157, 38,
+ 38, 43, 136, 123, 128, 198, 105, 159, 175, 66, 155, 150, 119, 254, 43,
+ 226, 225, 7, 237, 87, 94, 126, 208, 158, 218, 248, 65, 91, 149, 151,
+ 159, 132, 135, 31, 180, 75, 121, 231, 231, 16, 39, 120, 237, 100, 52,
+ 240, 131, 9, 188, 152, 233, 72, 98, 70, 2, 250, 74, 198, 10, 99,
+ 6, 182, 195, 243, 0, 31, 98, 237, 196, 71, 63, 204, 92, 75, 119,
+ 193, 254, 12, 249, 98, 25, 224, 157, 160, 76, 229, 124, 102, 140, 126,
+ 152, 89, 30, 249, 13, 231, 77, 144, 47, 158, 107, 0, 26, 233, 66,
+ 141, 209, 15, 51, 169, 55, 219, 225, 251, 230, 36, 99, 203, 204, 53,
+ 88, 251, 230, 140, 214, 15, 51, 207, 6, 19, 191, 151, 229, 163, 221,
+ 135, 160, 77, 203, 235, 147, 208, 198, 218, 248, 65, 251, 149, 151, 31,
+ 197, 195, 15, 218, 170, 188, 252, 160, 237, 180, 241, 131, 118, 41, 47,
+ 102, 32, 78, 240, 218, 201, 112, 224, 7, 190, 188, 152, 233, 68, 98,
+ 38, 103, 84, 160, 216, 115, 164, 48, 102, 96, 59, 92, 111, 26, 69,
+ 172, 157, 140, 208, 15, 51, 48, 175, 196, 245, 38, 66, 70, 14, 120,
+ 167, 28, 86, 78, 200, 8, 253, 48, 3, 243, 54, 172, 199, 72, 66,
+ 15, 64, 99, 93, 70, 232, 135, 25, 152, 23, 97, 61, 70, 150, 89,
+ 59, 97, 237, 27, 63, 92, 63, 204, 64, 159, 192, 107, 39, 35, 136,
+ 115, 44, 84, 7, 57, 151, 159, 203, 164, 136, 142, 79, 219, 79, 233,
+ 146, 183, 187, 176, 54, 38, 249, 113, 185, 174, 76, 138, 104, 200, 79,
+ 151, 28, 216, 133, 181, 39, 254, 205, 58, 186, 131, 156, 203, 27, 101,
+ 82, 68, 123, 2, 126, 186, 228, 147, 46, 172, 237, 200, 247, 227, 240,
+ 1, 255, 85, 209, 240, 253, 116, 205, 205, 32, 78, 240, 218, 137, 23,
+ 240, 131, 209, 188, 152, 113, 36, 49, 19, 63, 12, 244, 29, 42, 140,
+ 25, 216, 14, 175, 57, 12, 35, 214, 78, 134, 232, 135, 25, 114, 126,
+ 110, 78, 200, 136, 7, 239, 20, 207, 202, 177, 27, 162, 31, 102, 200,
+ 249, 57, 228, 139, 245, 0, 52, 210, 69, 238, 173, 31, 102, 200, 249,
+ 185, 249, 208, 50, 107, 39, 172, 125, 61, 189, 245, 195, 12, 154, 159,
+ 187, 176, 118, 199, 191, 203, 232, 35, 150, 135, 228, 118, 119, 44, 59,
+ 63, 239, 151, 184, 129, 90, 245, 35, 232, 176, 78, 107, 39, 101, 248,
+ 205, 152, 242, 219, 177, 236, 92, 23, 242, 75, 219, 106, 121, 68, 167,
+ 181, 19, 111, 98, 92, 248, 75, 44, 247, 218, 218, 205, 173, 236, 188,
+ 209, 243, 214, 6, 234, 95, 219, 20, 103, 157, 214, 78, 8, 126, 41,
+ 99, 197, 242, 42, 107, 162, 254, 152, 131, 237, 218, 190, 129, 10, 250,
+ 107, 142, 78, 53, 45, 136, 19, 124, 223, 156, 39, 160, 135, 243, 98,
+ 166, 51, 137, 25, 79, 208, 55, 103, 144, 48, 102, 96, 59, 60, 6,
+ 12, 38, 230, 51, 127, 233, 138, 153, 10, 90, 98, 39, 49, 150, 13,
+ 38, 198, 0, 64, 67, 153, 74, 127, 110, 172, 43, 102, 132, 101, 120,
+ 18, 50, 160, 222, 72, 23, 159, 70, 186, 98, 70, 7, 61, 6, 149,
+ 89, 59, 65, 246, 106, 168, 43, 102, 42, 240, 142, 51, 237, 140, 84,
+ 118, 183, 86, 182, 4, 152, 108, 211, 78, 174, 94, 87, 86, 253, 7,
+ 127, 75, 141, 47, 87, 129, 113, 87, 62, 176, 132, 138, 166, 87, 28,
+ 98, 51, 109, 26, 253, 127, 73, 158, 47, 13, 158, 119, 228, 235, 91,
+ 84, 59, 142, 254, 210, 137, 98, 177, 149, 132, 235, 103, 181, 95, 158,
+ 163, 199, 109, 11, 56, 204, 215, 247, 109, 189, 66, 122, 229, 194, 84,
+ 22, 127, 166, 204, 133, 201, 11, 148, 180, 73, 73, 37, 38, 253, 74,
+ 224, 17, 190, 190, 165, 38, 53, 24, 174, 86, 103, 129, 233, 144, 23,
+ 86, 140, 80, 13, 15, 217, 15, 250, 148, 161, 236, 215, 183, 81, 183,
+ 116, 77, 246, 3, 207, 59, 9, 217, 239, 253, 209, 98, 108, 63, 20,
+ 155, 160, 253, 46, 93, 174, 115, 68, 200, 126, 178, 69, 254, 71, 145,
+ 253, 190, 188, 183, 57, 138, 236, 215, 112, 162, 229, 81, 33, 251, 113,
+ 117, 62, 11, 76, 67, 251, 9, 213, 255, 144, 253, 32, 94, 144, 253,
+ 86, 104, 177, 223, 52, 29, 236, 183, 215, 179, 132, 26, 231, 114, 43,
+ 179, 172, 253, 154, 222, 243, 165, 31, 186, 243, 255, 182, 231, 133, 58,
+ 113, 180, 243, 221, 46, 110, 200, 126, 40, 22, 119, 252, 124, 142, 158,
+ 117, 224, 51, 239, 249, 153, 234, 245, 11, 233, 3, 123, 173, 78, 34,
+ 251, 117, 152, 116, 87, 185, 31, 249, 65, 133, 202, 204, 49, 251, 19,
+ 188, 251, 154, 39, 152, 214, 96, 184, 26, 161, 5, 166, 239, 23, 88,
+ 49, 66, 181, 67, 100, 63, 24, 11, 212, 253, 239, 207, 188, 73, 229,
+ 127, 252, 121, 19, 244, 191, 71, 183, 35, 165, 156, 253, 84, 237, 219,
+ 2, 255, 139, 183, 224, 239, 91, 217, 34, 142, 174, 184, 36, 10, 239,
+ 107, 70, 99, 207, 56, 224, 127, 179, 38, 205, 225, 223, 7, 106, 89,
+ 72, 23, 126, 24, 139, 247, 144, 54, 58, 31, 160, 164, 251, 1, 255,
+ 27, 226, 23, 200, 255, 91, 56, 192, 126, 92, 125, 209, 2, 211, 19,
+ 128, 255, 9, 213, 29, 241, 253, 77, 158, 220, 152, 71, 89, 130, 56,
+ 238, 197, 59, 230, 117, 37, 199, 188, 16, 208, 87, 86, 95, 120, 204,
+ 131, 237, 80, 28, 151, 53, 224, 218, 155, 215, 55, 220, 220, 10, 242,
+ 197, 99, 5, 160, 161, 76, 101, 46, 106, 101, 184, 185, 149, 136, 144,
+ 1, 245, 70, 186, 216, 89, 25, 110, 110, 5, 249, 146, 99, 158, 136,
+ 149, 33, 183, 52, 220, 220, 10, 218, 93, 223, 185, 149, 218, 25, 124,
+ 43, 253, 231, 86, 106, 121, 167, 149, 254, 115, 43, 181, 188, 211, 82,
+ 255, 185, 21, 153, 39, 66, 156, 32, 204, 136, 106, 5, 138, 139, 60,
+ 121, 49, 211, 141, 196, 140, 188, 94, 160, 152, 170, 43, 140, 25, 216,
+ 14, 249, 1, 85, 143, 107, 239, 89, 71, 87, 204, 152, 104, 244, 3,
+ 247, 71, 219, 241, 188, 135, 34, 100, 200, 193, 59, 201, 89, 57, 62,
+ 22, 186, 98, 70, 179, 140, 156, 254, 94, 105, 88, 143, 186, 132, 30,
+ 128, 70, 186, 132, 212, 214, 21, 51, 154, 101, 248, 72, 215, 226, 123,
+ 53, 168, 186, 234, 152, 145, 179, 246, 149, 213, 210, 21, 51, 154, 101,
+ 28, 174, 52, 83, 137, 153, 116, 214, 238, 214, 202, 150, 34, 209, 143,
+ 197, 77, 165, 208, 142, 200, 135, 16, 221, 243, 214, 110, 226, 185, 230,
+ 184, 155, 209, 40, 79, 106, 92, 247, 52, 106, 67, 189, 217, 115, 65,
+ 73, 59, 166, 140, 163, 190, 46, 123, 106, 207, 231, 127, 143, 90, 29,
+ 160, 56, 254, 10, 76, 59, 44, 52, 163, 133, 228, 34, 61, 224, 183,
+ 37, 245, 128, 223, 10, 233, 129, 104, 168, 7, 247, 92, 187, 30, 57,
+ 43, 34, 80, 27, 170, 223, 251, 232, 52, 164, 135, 91, 215, 117, 105,
+ 66, 122, 112, 252, 21, 152, 134, 122, 8, 201, 69, 122, 64, 255, 65,
+ 122, 44, 91, 217, 84, 10, 253, 1, 233, 129, 232, 43, 55, 119, 19,
+ 207, 181, 140, 191, 198, 121, 210, 133, 39, 83, 81, 27, 234, 68, 254,
+ 17, 37, 157, 249, 207, 56, 202, 104, 112, 78, 54, 159, 30, 121, 214,
+ 7, 40, 142, 191, 2, 211, 135, 22, 152, 209, 66, 114, 145, 30, 208,
+ 71, 145, 30, 219, 150, 52, 149, 66, 159, 67, 122, 32, 250, 76, 222,
+ 110, 226, 185, 102, 126, 222, 13, 242, 164, 147, 75, 167, 162, 54, 212,
+ 127, 141, 84, 244, 143, 3, 227, 40, 31, 121, 32, 111, 92, 219, 1,
+ 190, 7, 199, 95, 129, 233, 230, 224, 123, 8, 201, 69, 49, 17, 198,
+ 65, 124, 63, 87, 127, 128, 115, 75, 190, 152, 104, 111, 71, 198, 68,
+ 89, 205, 64, 113, 226, 64, 225, 152, 8, 219, 97, 156, 215, 36, 214,
+ 53, 6, 234, 151, 71, 60, 186, 102, 138, 99, 162, 136, 144, 33, 51,
+ 7, 99, 60, 43, 71, 62, 64, 191, 60, 194, 216, 246, 0, 94, 59,
+ 129, 124, 241, 218, 9, 124, 119, 86, 134, 231, 0, 253, 242, 136, 13,
+ 212, 39, 188, 22, 8, 249, 146, 49, 17, 202, 84, 126, 221, 254, 250,
+ 229, 17, 22, 118, 92, 189, 9, 218, 93, 91, 157, 31, 218, 180, 188,
+ 235, 6, 208, 198, 218, 248, 65, 251, 149, 151, 159, 39, 15, 63, 104,
+ 171, 242, 242, 131, 182, 211, 198, 15, 218, 165, 188, 235, 26, 16, 39,
+ 248, 126, 174, 222, 224, 187, 212, 226, 197, 140, 218, 30, 42, 69, 191,
+ 64, 177, 79, 95, 97, 204, 192, 118, 120, 109, 187, 31, 113, 63, 87,
+ 31, 195, 229, 222, 62, 132, 12, 5, 120, 39, 5, 43, 71, 214, 199,
+ 112, 185, 55, 228, 139, 245, 0, 52, 210, 197, 188, 143, 225, 114, 111,
+ 159, 190, 101, 238, 231, 98, 237, 155, 216, 219, 112, 185, 55, 180, 187,
+ 33, 215, 53, 100, 125, 12, 187, 174, 97, 222, 199, 176, 235, 26, 208,
+ 118, 134, 92, 215, 128, 56, 193, 251, 14, 123, 0, 63, 232, 207, 139,
+ 25, 181, 61, 39, 137, 189, 2, 197, 18, 15, 97, 204, 192, 118, 120,
+ 221, 185, 23, 177, 87, 215, 93, 63, 204, 236, 147, 89, 226, 49, 64,
+ 66, 200, 72, 4, 239, 148, 200, 202, 161, 220, 245, 195, 76, 161, 201,
+ 69, 110, 253, 220, 131, 208, 3, 208, 72, 151, 156, 158, 250, 97, 38,
+ 41, 185, 42, 183, 126, 238, 81, 102, 253, 156, 181, 175, 79, 79, 253,
+ 48, 179, 98, 115, 56, 183, 87, 215, 93, 123, 220, 133, 54, 45, 247,
+ 122, 55, 15, 63, 104, 191, 114, 175, 119, 247, 212, 206, 15, 218, 170,
+ 188, 252, 124, 120, 248, 65, 187, 148, 119, 156, 129, 56, 65, 152, 145,
+ 81, 192, 15, 122, 107, 192, 204, 4, 223, 80, 248, 195, 83, 51, 216,
+ 205, 186, 120, 15, 17, 232, 171, 96, 116, 216, 167, 213, 131, 24, 3,
+ 186, 19, 227, 12, 173, 223, 124, 245, 171, 127, 50, 183, 199, 181, 59,
+ 49, 6, 0, 26, 202, 84, 49, 208, 111, 190, 218, 212, 249, 45, 206,
+ 155, 124, 8, 25, 80, 111, 164, 139, 93, 13, 253, 230, 171, 143, 186,
+ 155, 74, 177, 30, 76, 153, 125, 90, 172, 12, 170, 186, 126, 243, 85,
+ 239, 38, 195, 240, 124, 21, 218, 29, 205, 43, 224, 254, 68, 104, 71,
+ 228, 55, 136, 30, 244, 247, 2, 154, 123, 174, 57, 238, 62, 76, 53,
+ 99, 102, 20, 61, 96, 219, 244, 99, 80, 251, 186, 111, 198, 51, 75,
+ 46, 173, 227, 237, 251, 125, 73, 20, 51, 117, 127, 33, 91, 123, 94,
+ 137, 233, 132, 211, 127, 19, 207, 249, 231, 71, 34, 66, 143, 111, 64,
+ 15, 248, 173, 144, 30, 136, 222, 4, 244, 224, 158, 107, 230, 183, 52,
+ 205, 140, 169, 61, 122, 1, 254, 221, 12, 212, 254, 9, 208, 99, 203,
+ 174, 16, 222, 190, 166, 75, 163, 152, 230, 14, 238, 110, 72, 15, 68,
+ 199, 3, 61, 184, 231, 252, 122, 64, 255, 65, 122, 124, 0, 122, 64,
+ 127, 192, 185, 50, 75, 215, 219, 178, 128, 230, 158, 107, 230, 151, 126,
+ 200, 140, 249, 247, 131, 20, 239, 23, 69, 237, 169, 119, 227, 153, 231,
+ 103, 242, 120, 223, 165, 30, 208, 195, 105, 177, 35, 254, 30, 136, 142,
+ 2, 122, 112, 207, 249, 245, 128, 62, 138, 235, 7, 64, 15, 232, 115,
+ 72, 15, 68, 143, 1, 223, 131, 123, 174, 153, 223, 79, 224, 87, 87,
+ 77, 123, 97, 61, 80, 251, 110, 224, 123, 4, 196, 143, 225, 223, 247,
+ 10, 252, 170, 75, 229, 121, 120, 239, 42, 162, 55, 0, 61, 184, 231,
+ 252, 121, 4, 140, 131, 184, 134, 87, 5, 224, 188, 7, 127, 76, 116,
+ 32, 235, 75, 102, 96, 126, 91, 77, 135, 26, 158, 25, 81, 251, 50,
+ 227, 218, 231, 84, 213, 47, 143, 200, 74, 94, 134, 199, 95, 138, 144,
+ 33, 7, 239, 36, 103, 229, 248, 84, 213, 47, 143, 24, 172, 136, 199,
+ 245, 53, 200, 23, 235, 1, 104, 164, 75, 81, 21, 253, 242, 136, 152,
+ 167, 117, 113, 76, 164, 170, 149, 169, 225, 177, 246, 149, 85, 209, 47,
+ 143, 216, 188, 191, 19, 206, 35, 160, 221, 181, 141, 171, 208, 166, 229,
+ 30, 167, 121, 248, 65, 251, 149, 151, 31, 180, 167, 214, 189, 181, 192,
+ 86, 229, 229, 39, 227, 225, 7, 237, 82, 222, 60, 2, 226, 4, 255,
+ 110, 65, 133, 64, 49, 196, 16, 31, 102, 58, 146, 245, 135, 202, 160,
+ 109, 37, 29, 106, 60, 149, 9, 63, 168, 204, 181, 143, 23, 235, 135,
+ 25, 89, 225, 255, 48, 102, 68, 132, 12, 25, 120, 39, 25, 43, 71,
+ 34, 214, 15, 51, 155, 54, 137, 79, 98, 61, 42, 17, 122, 64, 189,
+ 89, 25, 41, 21, 245, 195, 204, 3, 207, 35, 156, 30, 149, 202, 212,
+ 120, 88, 251, 82, 21, 245, 195, 76, 252, 137, 86, 24, 51, 208, 238,
+ 218, 124, 8, 218, 180, 188, 62, 41, 225, 225, 7, 237, 87, 94, 126,
+ 208, 158, 218, 248, 65, 91, 149, 123, 110, 192, 195, 15, 218, 165, 188,
+ 152, 129, 56, 193, 185, 183, 17, 248, 46, 85, 248, 49, 211, 137, 144,
+ 77, 129, 190, 114, 19, 97, 204, 192, 118, 120, 12, 48, 37, 214, 138,
+ 76, 244, 195, 204, 191, 189, 250, 98, 95, 131, 124, 241, 24, 0, 104,
+ 40, 83, 89, 35, 49, 214, 15, 51, 37, 155, 190, 227, 252, 158, 34,
+ 100, 64, 189, 145, 46, 33, 198, 250, 97, 166, 198, 254, 255, 112, 126,
+ 15, 249, 146, 152, 161, 144, 189, 140, 245, 195, 76, 147, 248, 48, 140,
+ 25, 104, 119, 109, 62, 4, 109, 170, 139, 15, 145, 53, 20, 104, 99,
+ 109, 252, 160, 253, 202, 203, 47, 132, 135, 31, 180, 85, 121, 249, 137,
+ 120, 248, 65, 187, 232, 202, 15, 231, 102, 70, 68, 141, 167, 29, 240,
+ 131, 10, 252, 152, 113, 36, 101, 131, 190, 146, 14, 194, 152, 129, 237,
+ 240, 24, 32, 34, 106, 60, 182, 250, 97, 134, 156, 175, 66, 190, 184,
+ 198, 3, 223, 201, 136, 141, 207, 182, 250, 97, 134, 156, 175, 66, 190,
+ 184, 198, 3, 104, 164, 75, 78, 123, 253, 48, 67, 206, 87, 37, 29,
+ 202, 212, 120, 88, 251, 250, 180, 215, 15, 51, 104, 190, 234, 194, 218,
+ 29, 249, 80, 142, 175, 88, 222, 114, 235, 138, 63, 230, 171, 223, 35,
+ 79, 82, 59, 102, 228, 185, 234, 20, 199, 9, 126, 149, 198, 137, 229,
+ 3, 91, 159, 251, 99, 222, 24, 15, 248, 85, 221, 87, 55, 91, 167,
+ 26, 79, 123, 142, 159, 221, 26, 177, 60, 226, 86, 190, 91, 217, 249,
+ 219, 217, 169, 39, 169, 61, 63, 90, 73, 117, 202, 29, 9, 126, 150,
+ 19, 196, 242, 255, 242, 199, 252, 49, 143, 122, 22, 113, 146, 138, 24,
+ 214, 95, 183, 243, 216, 237, 8, 204, 88, 3, 63, 48, 226, 199, 76,
+ 103, 178, 254, 0, 250, 42, 218, 234, 80, 227, 105, 71, 212, 70, 108,
+ 136, 243, 216, 109, 244, 59, 143, 173, 182, 94, 97, 67, 212, 120, 0,
+ 13, 101, 42, 125, 174, 181, 126, 231, 177, 213, 244, 32, 100, 64, 189,
+ 145, 46, 178, 86, 250, 157, 199, 86, 211, 163, 109, 153, 26, 15, 43,
+ 195, 167, 165, 126, 231, 177, 209, 90, 66, 17, 107, 119, 116, 6, 53,
+ 78, 203, 222, 193, 1, 58, 236, 29, 172, 232, 89, 66, 45, 202, 247,
+ 255, 99, 239, 224, 140, 60, 95, 250, 224, 3, 127, 222, 186, 192, 249,
+ 218, 113, 116, 141, 84, 132, 213, 36, 92, 79, 26, 84, 114, 157, 54,
+ 9, 203, 227, 173, 15, 173, 168, 37, 98, 184, 250, 147, 5, 166, 79,
+ 109, 177, 97, 132, 234, 82, 248, 60, 118, 107, 206, 6, 43, 181, 216,
+ 96, 164, 14, 54, 240, 0, 54, 72, 76, 77, 116, 41, 107, 131, 51,
+ 192, 6, 75, 210, 19, 121, 239, 37, 217, 10, 108, 176, 157, 57, 135,
+ 239, 91, 71, 241, 165, 43, 176, 65, 250, 254, 186, 188, 251, 0, 150,
+ 1, 27, 112, 181, 43, 11, 76, 67, 27, 8, 213, 180, 240, 121, 236,
+ 86, 156, 13, 70, 107, 177, 193, 248, 52, 97, 27, 56, 140, 40, 161,
+ 236, 141, 15, 101, 149, 181, 193, 141, 103, 190, 244, 114, 230, 16, 239,
+ 247, 216, 104, 22, 71, 159, 255, 144, 143, 247, 144, 162, 152, 232, 246,
+ 253, 58, 189, 252, 103, 43, 222, 154, 140, 4, 216, 128, 171, 123, 89,
+ 96, 58, 19, 216, 64, 168, 30, 134, 207, 99, 183, 228, 108, 176, 66,
+ 203, 62, 208, 80, 29, 246, 129, 30, 2, 126, 48, 220, 39, 230, 143,
+ 125, 160, 189, 238, 250, 210, 117, 164, 252, 123, 57, 71, 3, 63, 8,
+ 184, 51, 6, 239, 3, 69, 113, 188, 26, 240, 131, 162, 161, 253, 121,
+ 251, 198, 2, 27, 112, 53, 51, 11, 76, 67, 63, 16, 170, 165, 225,
+ 49, 192, 154, 56, 143, 221, 20, 196, 181, 118, 252, 99, 64, 87, 50,
+ 62, 129, 190, 138, 230, 58, 140, 1, 214, 68, 236, 108, 65, 156, 95,
+ 104, 174, 95, 222, 4, 235, 193, 56, 118, 182, 32, 198, 0, 64, 67,
+ 153, 202, 70, 205, 245, 203, 155, 96, 173, 22, 235, 65, 200, 128, 122,
+ 35, 93, 226, 155, 233, 151, 55, 193, 58, 42, 214, 163, 121, 153, 49,
+ 128, 149, 33, 105, 166, 95, 222, 4, 107, 156, 56, 151, 111, 206, 229,
+ 17, 241, 62, 187, 229, 92, 93, 93, 38, 69, 180, 220, 162, 34, 205,
+ 87, 111, 87, 59, 143, 77, 240, 147, 249, 238, 150, 115, 245, 109, 153,
+ 20, 209, 150, 128, 31, 95, 221, 91, 237, 60, 118, 51, 142, 31, 53,
+ 110, 183, 156, 171, 51, 203, 164, 136, 126, 89, 171, 34, 205, 87, 127,
+ 86, 171, 31, 16, 252, 82, 128, 190, 92, 189, 87, 38, 69, 116, 18,
+ 120, 63, 190, 58, 176, 218, 121, 236, 166, 68, 77, 43, 7, 248, 129,
+ 53, 63, 102, 186, 17, 223, 67, 2, 250, 74, 62, 232, 112, 30, 187,
+ 41, 49, 15, 144, 16, 251, 150, 100, 122, 238, 91, 90, 83, 11, 207,
+ 53, 32, 95, 44, 3, 240, 133, 50, 149, 243, 153, 34, 253, 48, 179,
+ 181, 225, 99, 78, 134, 140, 152, 107, 0, 189, 145, 46, 84, 145, 126,
+ 152, 241, 120, 189, 158, 187, 251, 233, 67, 153, 185, 6, 107, 35, 234,
+ 134, 126, 152, 153, 229, 74, 236, 91, 146, 241, 236, 91, 2, 54, 45,
+ 239, 252, 23, 218, 88, 27, 63, 104, 191, 242, 242, 163, 120, 248, 65,
+ 91, 149, 155, 223, 13, 237, 252, 160, 93, 202, 59, 63, 135, 56, 65,
+ 152, 9, 145, 4, 137, 19, 155, 242, 98, 70, 185, 217, 15, 215, 91,
+ 64, 95, 74, 161, 67, 77, 43, 135, 168, 55, 61, 38, 206, 99, 167,
+ 234, 135, 153, 108, 199, 5, 220, 218, 201, 99, 162, 222, 4, 222, 9,
+ 202, 84, 142, 101, 169, 250, 97, 230, 212, 241, 177, 120, 12, 128, 124,
+ 177, 30, 80, 6, 210, 37, 85, 207, 113, 102, 103, 33, 167, 135, 162,
+ 204, 218, 9, 107, 223, 248, 20, 253, 48, 51, 33, 117, 56, 119, 30,
+ 59, 85, 187, 15, 65, 155, 150, 183, 206, 26, 194, 195, 15, 218, 175,
+ 188, 252, 68, 60, 252, 160, 173, 202, 203, 15, 218, 78, 235, 189, 36,
+ 192, 46, 229, 173, 3, 67, 156, 224, 123, 57, 69, 65, 98, 121, 14,
+ 63, 102, 200, 61, 24, 137, 118, 160, 175, 81, 144, 240, 190, 37, 208,
+ 14, 255, 86, 178, 57, 215, 222, 211, 55, 72, 175, 61, 24, 100, 110,
+ 6, 249, 226, 223, 124, 6, 52, 148, 169, 204, 109, 124, 130, 244, 218,
+ 131, 65, 230, 102, 118, 132, 12, 168, 55, 210, 69, 70, 7, 233, 181,
+ 7, 131, 204, 205, 32, 95, 181, 223, 124, 102, 101, 196, 83, 65, 122,
+ 237, 193, 64, 185, 89, 58, 107, 119, 188, 230, 223, 35, 214, 77, 83,
+ 110, 86, 117, 207, 117, 169, 208, 94, 8, 207, 239, 245, 168, 115, 174,
+ 173, 88, 31, 166, 168, 21, 107, 157, 148, 244, 209, 235, 155, 169, 6,
+ 99, 103, 240, 230, 97, 45, 219, 63, 163, 56, 254, 230, 56, 15, 28,
+ 20, 212, 145, 214, 117, 15, 6, 252, 182, 72, 15, 151, 150, 177, 110,
+ 154, 114, 194, 46, 7, 175, 75, 133, 246, 66, 28, 104, 96, 73, 37,
+ 44, 104, 138, 245, 184, 62, 182, 161, 146, 110, 148, 179, 153, 170, 243,
+ 169, 26, 175, 30, 73, 29, 158, 81, 28, 127, 115, 156, 127, 46, 11,
+ 238, 72, 235, 186, 7, 3, 250, 15, 210, 99, 238, 224, 88, 55, 77,
+ 185, 104, 215, 127, 175, 75, 133, 246, 66, 108, 127, 81, 143, 154, 119,
+ 195, 14, 235, 113, 184, 66, 47, 37, 29, 7, 190, 135, 113, 98, 44,
+ 175, 30, 63, 108, 158, 81, 28, 127, 115, 156, 247, 158, 12, 236, 72,
+ 235, 186, 7, 3, 250, 40, 210, 163, 158, 117, 172, 155, 166, 28, 56,
+ 44, 245, 186, 84, 104, 47, 132, 125, 35, 75, 202, 51, 18, 253, 78,
+ 5, 69, 197, 175, 85, 253, 222, 69, 51, 240, 61, 34, 111, 133, 240,
+ 230, 207, 167, 192, 247, 224, 248, 155, 227, 124, 123, 61, 248, 30, 186,
+ 238, 193, 128, 113, 16, 197, 196, 20, 81, 176, 24, 198, 72, 190, 152,
+ 72, 238, 193, 144, 229, 4, 137, 139, 140, 131, 133, 215, 147, 115, 136,
+ 152, 168, 224, 248, 203, 52, 244, 45, 87, 157, 63, 221, 7, 231, 197,
+ 144, 47, 142, 137, 128, 134, 50, 149, 86, 209, 73, 134, 246, 60, 98,
+ 233, 254, 48, 44, 195, 142, 144, 1, 245, 70, 186, 36, 26, 5, 235,
+ 149, 71, 28, 9, 251, 136, 215, 18, 32, 95, 181, 152, 200, 202, 176,
+ 211, 73, 134, 246, 60, 226, 248, 16, 110, 47, 39, 180, 187, 182, 113,
+ 21, 218, 180, 188, 227, 180, 57, 15, 63, 104, 191, 242, 242, 131, 246,
+ 212, 198, 15, 218, 170, 188, 252, 236, 120, 248, 65, 187, 148, 55, 143,
+ 128, 56, 193, 231, 108, 250, 4, 139, 33, 134, 52, 98, 38, 116, 82,
+ 192, 68, 118, 51, 39, 254, 158, 160, 111, 226, 0, 97, 204, 192, 118,
+ 220, 249, 20, 174, 125, 74, 255, 96, 189, 242, 8, 133, 127, 50, 113,
+ 62, 133, 147, 33, 1, 52, 148, 169, 204, 93, 251, 5, 235, 149, 71,
+ 4, 56, 191, 197, 152, 145, 16, 50, 160, 222, 72, 151, 156, 190, 193,
+ 122, 229, 17, 15, 137, 181, 49, 200, 87, 237, 183, 87, 88, 25, 138,
+ 62, 193, 122, 229, 17, 94, 196, 94, 78, 104, 119, 114, 47, 39, 180,
+ 35, 242, 27, 68, 123, 254, 189, 128, 230, 158, 107, 142, 187, 247, 82,
+ 205, 152, 93, 209, 203, 216, 54, 253, 24, 212, 190, 214, 155, 241, 76,
+ 251, 211, 71, 120, 251, 194, 189, 156, 159, 198, 162, 122, 244, 74, 76,
+ 195, 189, 156, 220, 115, 254, 113, 11, 126, 91, 82, 15, 248, 173, 144,
+ 30, 136, 246, 2, 122, 112, 207, 53, 243, 83, 0, 61, 250, 159, 173,
+ 131, 239, 13, 69, 237, 173, 128, 30, 251, 7, 222, 18, 220, 147, 122,
+ 112, 80, 63, 87, 164, 7, 162, 161, 30, 220, 115, 126, 61, 160, 255,
+ 32, 61, 190, 0, 61, 30, 18, 123, 57, 17, 125, 22, 232, 241, 80,
+ 160, 118, 253, 46, 205, 140, 105, 117, 219, 30, 239, 129, 68, 237, 135,
+ 190, 29, 207, 56, 154, 63, 227, 205, 105, 170, 44, 141, 98, 190, 92,
+ 172, 128, 247, 164, 34, 122, 25, 208, 131, 123, 206, 175, 7, 244, 81,
+ 242, 123, 120, 17, 123, 57, 17, 61, 22, 232, 225, 37, 80, 127, 46,
+ 1, 223, 99, 78, 170, 7, 214, 3, 181, 119, 2, 223, 227, 68, 170,
+ 240, 94, 206, 7, 89, 220, 94, 78, 68, 195, 189, 156, 220, 115, 254,
+ 60, 2, 198, 65, 124, 142, 202, 29, 140, 141, 162, 96, 254, 152, 232,
+ 64, 156, 241, 233, 29, 44, 246, 233, 37, 28, 19, 97, 59, 92, 147,
+ 238, 205, 181, 47, 242, 208, 47, 143, 232, 221, 105, 30, 254, 173, 115,
+ 31, 66, 134, 2, 188, 147, 130, 149, 35, 243, 208, 47, 143, 120, 92,
+ 181, 29, 222, 203, 9, 249, 98, 61, 0, 141, 116, 49, 247, 208, 47,
+ 143, 88, 166, 216, 197, 213, 214, 123, 169, 199, 68, 5, 107, 223, 68,
+ 119, 253, 242, 136, 245, 49, 83, 184, 115, 84, 30, 218, 199, 85, 104,
+ 211, 242, 142, 211, 50, 30, 126, 208, 126, 229, 206, 75, 120, 248, 65,
+ 91, 149, 59, 47, 113, 215, 206, 15, 218, 165, 188, 121, 4, 196, 9,
+ 222, 47, 64, 3, 63, 232, 35, 128, 153, 142, 68, 61, 162, 103, 176,
+ 88, 210, 67, 24, 51, 176, 29, 30, 227, 123, 18, 121, 68, 119, 253,
+ 48, 115, 183, 105, 12, 246, 103, 9, 33, 35, 17, 188, 83, 34, 43,
+ 135, 234, 174, 31, 102, 206, 116, 120, 135, 253, 25, 242, 197, 122, 0,
+ 26, 233, 146, 195, 232, 135, 25, 199, 119, 151, 185, 115, 84, 61, 212,
+ 49, 147, 200, 218, 215, 135, 209, 15, 51, 89, 199, 164, 220, 30, 155,
+ 238, 218, 125, 8, 218, 180, 188, 62, 73, 241, 240, 131, 246, 43, 47,
+ 63, 104, 79, 109, 252, 160, 173, 202, 203, 207, 135, 135, 31, 180, 75,
+ 121, 49, 3, 113, 130, 115, 111, 87, 224, 7, 238, 2, 152, 233, 68,
+ 172, 253, 129, 190, 137, 82, 97, 204, 192, 118, 120, 12, 160, 184, 246,
+ 118, 82, 253, 48, 19, 186, 182, 18, 55, 6, 80, 196, 24, 0, 104,
+ 40, 83, 153, 123, 187, 233, 135, 153, 243, 117, 55, 114, 231, 168, 8,
+ 25, 80, 111, 164, 139, 167, 155, 126, 152, 73, 108, 31, 200, 205, 33,
+ 164, 234, 152, 241, 97, 101, 40, 92, 245, 195, 140, 223, 26, 226, 238,
+ 94, 169, 118, 31, 130, 54, 45, 239, 90, 12, 180, 177, 214, 251, 169,
+ 129, 253, 202, 203, 207, 147, 135, 31, 180, 85, 121, 249, 65, 219, 105,
+ 227, 7, 237, 82, 222, 181, 34, 136, 19, 156, 155, 117, 3, 126, 64,
+ 11, 96, 198, 145, 200, 27, 92, 128, 111, 58, 235, 144, 155, 185, 16,
+ 254, 236, 66, 228, 102, 78, 250, 97, 134, 156, 175, 250, 16, 50, 20,
+ 224, 157, 20, 172, 28, 153, 147, 126, 152, 33, 231, 171, 144, 47, 214,
+ 3, 208, 72, 23, 115, 39, 253, 48, 67, 206, 87, 125, 156, 203, 228,
+ 102, 172, 125, 19, 187, 233, 135, 25, 47, 98, 47, 39, 180, 59, 185,
+ 151, 211, 98, 235, 138, 63, 230, 171, 112, 47, 103, 236, 140, 188, 44,
+ 157, 114, 51, 130, 31, 220, 203, 185, 164, 245, 185, 63, 230, 141, 112,
+ 47, 103, 215, 125, 117, 117, 218, 147, 96, 78, 240, 131, 123, 57, 195,
+ 137, 189, 156, 15, 137, 189, 156, 73, 58, 238, 229, 132, 182, 35, 247,
+ 114, 222, 36, 246, 114, 122, 17, 123, 57, 195, 117, 220, 203, 9, 113,
+ 130, 49, 227, 0, 252, 192, 85, 0, 51, 157, 137, 188, 161, 43, 24,
+ 151, 186, 232, 144, 155, 117, 37, 114, 154, 174, 68, 251, 206, 193, 6,
+ 219, 203, 41, 33, 100, 36, 130, 119, 74, 100, 229, 40, 58, 5, 27,
+ 108, 47, 39, 228, 139, 245, 0, 52, 210, 69, 222, 49, 216, 96, 123,
+ 57, 37, 93, 202, 228, 102, 172, 125, 19, 29, 130, 13, 182, 151, 19,
+ 218, 221, 80, 123, 57, 39, 229, 251, 255, 177, 143, 17, 238, 229, 92,
+ 245, 192, 159, 119, 31, 35, 220, 203, 89, 154, 178, 2, 239, 99, 68,
+ 88, 133, 123, 57, 95, 204, 202, 227, 173, 241, 192, 189, 156, 92, 253,
+ 201, 2, 211, 112, 255, 154, 80, 93, 10, 217, 0, 250, 133, 161, 246,
+ 114, 94, 79, 77, 252, 99, 63, 43, 220, 203, 153, 145, 158, 200, 187,
+ 198, 2, 247, 114, 222, 103, 206, 225, 253, 172, 40, 190, 192, 189, 156,
+ 138, 253, 117, 121, 235, 42, 112, 47, 39, 87, 187, 178, 192, 52, 180,
+ 129, 80, 77, 11, 239, 233, 237, 24, 108, 176, 189, 156, 29, 180, 236,
+ 229, 92, 166, 195, 94, 206, 115, 196, 94, 206, 135, 196, 94, 206, 101,
+ 58, 236, 229, 124, 72, 236, 229, 124, 72, 236, 229, 124, 168, 227, 94,
+ 78, 136, 171, 255, 31, 246, 114, 250, 19, 123, 57, 189, 136, 189, 156,
+ 239, 116, 216, 203, 233, 69, 236, 229, 244, 34, 246, 114, 122, 233, 184,
+ 151, 19, 198, 125, 124, 127, 251, 104, 16, 215, 186, 9, 140, 1, 93,
+ 137, 248, 100, 15, 98, 237, 88, 29, 198, 0, 123, 34, 118, 218, 19,
+ 115, 13, 59, 253, 242, 38, 88, 15, 198, 177, 147, 144, 145, 8, 248,
+ 38, 178, 114, 236, 198, 234, 151, 55, 193, 90, 45, 183, 239, 129, 144,
+ 1, 248, 34, 93, 228, 99, 244, 203, 155, 96, 29, 149, 251, 45, 146,
+ 50, 99, 0, 107, 35, 207, 49, 250, 229, 77, 176, 198, 137, 231, 26,
+ 118, 193, 196, 125, 235, 187, 229, 92, 93, 93, 38, 69, 244, 69, 139,
+ 138, 52, 95, 189, 93, 109, 237, 105, 108, 176, 218, 222, 80, 174, 190,
+ 45, 147, 34, 26, 238, 13, 229, 171, 123, 171, 221, 207, 53, 134, 227,
+ 103, 238, 183, 91, 206, 213, 153, 101, 82, 68, 167, 212, 174, 72, 243,
+ 213, 159, 213, 238, 231, 34, 248, 193, 189, 156, 92, 189, 87, 38, 69,
+ 52, 220, 203, 201, 87, 7, 86, 187, 191, 125, 52, 135, 153, 248, 225,
+ 192, 15, 28, 4, 48, 211, 141, 184, 91, 28, 244, 205, 25, 41, 140,
+ 25, 216, 14, 223, 123, 62, 138, 107, 239, 51, 82, 63, 204, 148, 100,
+ 54, 200, 226, 126, 139, 36, 152, 248, 45, 146, 96, 49, 148, 169, 156,
+ 207, 140, 208, 15, 51, 197, 15, 189, 178, 185, 223, 34, 33, 244, 0,
+ 239, 142, 116, 145, 141, 208, 15, 51, 84, 158, 59, 167, 199, 72, 117,
+ 204, 120, 178, 50, 204, 71, 232, 135, 153, 171, 47, 231, 112, 191, 125,
+ 59, 82, 251, 124, 21, 218, 180, 188, 243, 95, 104, 99, 109, 252, 160,
+ 253, 202, 203, 79, 198, 195, 15, 218, 170, 188, 252, 204, 121, 248, 65,
+ 187, 148, 119, 126, 14, 113, 130, 127, 143, 202, 27, 248, 193, 104, 126,
+ 204, 192, 205, 156, 248, 183, 111, 65, 223, 248, 161, 194, 152, 129, 237,
+ 240, 111, 120, 12, 227, 218, 75, 134, 234, 135, 153, 230, 138, 219, 89,
+ 220, 111, 145, 4, 19, 191, 69, 2, 116, 26, 174, 226, 157, 50, 68,
+ 63, 204, 156, 43, 110, 146, 197, 253, 22, 9, 161, 7, 120, 119, 164,
+ 11, 53, 68, 63, 204, 212, 59, 158, 229, 198, 253, 22, 137, 58, 102,
+ 204, 89, 25, 57, 222, 250, 97, 102, 67, 149, 96, 140, 25, 104, 119,
+ 109, 62, 4, 109, 90, 222, 58, 43, 180, 177, 54, 126, 208, 126, 229,
+ 174, 43, 243, 240, 131, 182, 42, 119, 93, 217, 91, 59, 63, 104, 151,
+ 242, 214, 129, 33, 78, 240, 190, 165, 8, 224, 7, 195, 5, 48, 67,
+ 236, 193, 200, 241, 2, 241, 124, 176, 48, 102, 96, 59, 60, 6, 120,
+ 17, 227, 204, 32, 253, 246, 96, 144, 185, 153, 39, 33, 35, 7, 188,
+ 83, 14, 43, 39, 228, 47, 253, 246, 96, 144, 185, 25, 228, 203, 253,
+ 22, 9, 208, 157, 149, 33, 243, 212, 111, 15, 6, 153, 155, 121, 14,
+ 86, 199, 76, 14, 107, 95, 187, 72, 253, 246, 96, 160, 220, 44, 157,
+ 181, 59, 90, 43, 111, 238, 24, 235, 166, 41, 55, 171, 149, 121, 93,
+ 42, 180, 23, 226, 98, 85, 75, 74, 116, 106, 4, 59, 142, 80, 84,
+ 230, 165, 137, 74, 250, 197, 245, 205, 84, 175, 128, 37, 188, 103, 145,
+ 131, 109, 159, 81, 28, 127, 115, 156, 7, 126, 8, 234, 72, 235, 186,
+ 7, 3, 126, 91, 164, 199, 246, 14, 177, 110, 154, 114, 66, 199, 172,
+ 235, 82, 161, 189, 16, 29, 106, 89, 82, 135, 110, 254, 204, 68, 122,
+ 84, 114, 106, 167, 148, 95, 12, 244, 248, 17, 190, 153, 55, 63, 85,
+ 0, 61, 56, 254, 230, 56, 255, 108, 27, 220, 145, 214, 117, 15, 6,
+ 244, 31, 164, 71, 146, 67, 172, 155, 166, 92, 116, 45, 248, 30, 66,
+ 123, 33, 246, 86, 183, 164, 106, 143, 246, 195, 123, 57, 127, 14, 155,
+ 170, 164, 223, 3, 61, 30, 55, 90, 198, 155, 199, 38, 2, 61, 56,
+ 254, 230, 56, 239, 173, 10, 244, 208, 117, 15, 6, 244, 81, 164, 135,
+ 168, 101, 172, 155, 166, 28, 184, 231, 201, 235, 82, 161, 189, 16, 254,
+ 141, 44, 169, 102, 191, 67, 241, 94, 206, 150, 231, 166, 41, 233, 198,
+ 57, 155, 169, 201, 245, 166, 240, 230, 207, 251, 59, 60, 163, 56, 254,
+ 230, 56, 223, 94, 1, 244, 208, 117, 15, 6, 140, 131, 248, 76, 200,
+ 92, 128, 115, 111, 129, 152, 72, 236, 193, 176, 3, 125, 83, 230, 235,
+ 176, 47, 45, 130, 195, 121, 74, 56, 215, 158, 154, 175, 95, 30, 177,
+ 33, 203, 18, 231, 197, 144, 47, 222, 203, 9, 104, 40, 83, 25, 83,
+ 230, 233, 151, 71, 188, 173, 181, 19, 199, 93, 59, 66, 6, 212, 27,
+ 233, 226, 51, 79, 191, 60, 98, 113, 238, 75, 44, 3, 242, 85, 219,
+ 203, 201, 202, 40, 154, 171, 95, 30, 225, 182, 125, 46, 206, 35, 160,
+ 221, 181, 142, 171, 192, 166, 229, 30, 167, 231, 105, 231, 7, 237, 87,
+ 238, 245, 95, 30, 126, 208, 86, 229, 229, 7, 109, 167, 141, 31, 180,
+ 75, 121, 243, 8, 136, 19, 140, 153, 233, 192, 15, 34, 52, 96, 198,
+ 127, 194, 228, 153, 196, 205, 156, 72, 118, 209, 156, 96, 113, 200, 236,
+ 96, 177, 191, 127, 75, 185, 191, 127, 51, 230, 68, 252, 130, 236, 206,
+ 61, 227, 165, 101, 49, 3, 219, 33, 63, 8, 153, 195, 241, 247, 12,
+ 211, 228, 7, 240, 221, 45, 152, 221, 173, 26, 102, 190, 19, 253, 112,
+ 229, 171, 243, 127, 165, 151, 225, 49, 62, 132, 144, 81, 4, 222, 169,
+ 136, 149, 99, 55, 75, 187, 12, 143, 234, 21, 50, 31, 205, 173, 237,
+ 198, 87, 231, 95, 253, 239, 18, 44, 3, 242, 197, 122, 0, 26, 233,
+ 98, 62, 83, 187, 140, 47, 61, 46, 103, 30, 107, 83, 81, 202, 87,
+ 231, 191, 120, 115, 50, 206, 35, 66, 102, 171, 99, 6, 202, 84, 254,
+ 59, 157, 71, 198, 73, 47, 233, 248, 16, 153, 148, 175, 206, 223, 255,
+ 74, 24, 174, 243, 67, 187, 147, 191, 27, 14, 237, 136, 248, 33, 90,
+ 121, 47, 39, 126, 46, 18, 173, 17, 181, 17, 237, 22, 217, 136, 246,
+ 138, 218, 225, 184, 251, 32, 213, 140, 9, 111, 126, 130, 187, 151, 147,
+ 109, 111, 246, 121, 4, 211, 123, 113, 36, 239, 24, 250, 181, 234, 100,
+ 38, 236, 107, 7, 182, 205, 124, 38, 231, 157, 137, 146, 54, 41, 137,
+ 102, 206, 183, 190, 198, 91, 31, 47, 53, 89, 194, 200, 54, 206, 195,
+ 119, 72, 34, 58, 228, 197, 26, 226, 57, 127, 125, 23, 250, 5, 105,
+ 3, 248, 157, 145, 13, 16, 61, 24, 216, 128, 123, 174, 217, 6, 143,
+ 224, 126, 214, 12, 57, 182, 1, 106, 95, 29, 216, 64, 252, 112, 182,
+ 160, 13, 58, 15, 107, 140, 109, 224, 61, 249, 63, 23, 100, 131, 237,
+ 212, 10, 65, 27, 68, 244, 219, 234, 140, 108, 128, 232, 105, 192, 6,
+ 220, 115, 126, 27, 64, 191, 69, 54, 248, 14, 108, 0, 253, 16, 217,
+ 0, 209, 211, 129, 13, 184, 231, 208, 6, 118, 192, 6, 221, 128, 13,
+ 156, 48, 191, 246, 105, 102, 140, 171, 243, 30, 188, 23, 22, 181, 239,
+ 1, 108, 32, 218, 235, 205, 155, 131, 124, 6, 54, 24, 48, 214, 196,
+ 13, 217, 224, 242, 195, 93, 74, 123, 252, 254, 25, 205, 120, 187, 121,
+ 184, 10, 217, 192, 204, 99, 141, 19, 178, 1, 162, 161, 13, 184, 231,
+ 252, 54, 128, 184, 34, 253, 0, 226, 4, 217, 0, 209, 127, 1, 27,
+ 112, 207, 161, 13, 194, 128, 13, 102, 2, 27, 204, 192, 252, 242, 129,
+ 31, 228, 62, 8, 197, 251, 79, 81, 251, 170, 192, 6, 213, 139, 103,
+ 243, 230, 47, 95, 128, 13, 58, 204, 68, 251, 240, 231, 51, 61, 62,
+ 169, 206, 195, 66, 63, 40, 253, 16, 41, 21, 178, 193, 236, 111, 145,
+ 120, 239, 42, 162, 33, 22, 184, 231, 252, 121, 19, 140, 251, 248, 252,
+ 249, 20, 16, 215, 230, 10, 141, 1, 14, 92, 124, 10, 5, 237, 167,
+ 233, 48, 6, 132, 18, 177, 51, 148, 136, 101, 211, 116, 29, 3, 180,
+ 220, 169, 8, 240, 142, 99, 39, 33, 163, 8, 240, 45, 98, 229, 196,
+ 135, 232, 58, 6, 104, 150, 1, 241, 132, 245, 152, 70, 232, 1, 104,
+ 164, 75, 202, 84, 93, 199, 0, 205, 50, 160, 191, 98, 61, 166, 149,
+ 25, 3, 88, 27, 81, 83, 117, 29, 3, 52, 203, 128, 254, 128, 207,
+ 170, 78, 227, 242, 8, 179, 119, 127, 203, 185, 184, 41, 147, 34, 250,
+ 16, 149, 73, 241, 197, 83, 181, 179, 170, 33, 234, 252, 184, 24, 36,
+ 147, 34, 58, 13, 240, 227, 139, 77, 106, 245, 156, 169, 234, 252, 56,
+ 60, 203, 164, 136, 134, 252, 248, 112, 174, 86, 207, 41, 195, 143, 195,
+ 134, 76, 138, 104, 168, 47, 31, 102, 212, 238, 84, 156, 194, 97, 70,
+ 22, 8, 252, 96, 186, 16, 102, 58, 114, 231, 207, 65, 95, 121, 176,
+ 48, 102, 96, 59, 124, 54, 124, 50, 145, 55, 5, 27, 14, 51, 144,
+ 47, 62, 27, 14, 104, 40, 83, 185, 63, 34, 200, 112, 152, 161, 8,
+ 25, 80, 111, 164, 75, 72, 144, 225, 48, 3, 249, 170, 221, 169, 136,
+ 236, 21, 100, 56, 204, 64, 187, 35, 31, 146, 139, 78, 158, 212, 132,
+ 25, 201, 187, 249, 58, 99, 6, 218, 152, 228, 167, 9, 51, 144, 159,
+ 174, 152, 9, 41, 195, 79, 19, 102, 40, 192, 79, 87, 204, 136, 202,
+ 240, 211, 132, 25, 17, 224, 167, 43, 102, 32, 78, 240, 239, 60, 250,
+ 3, 63, 152, 34, 132, 153, 78, 220, 247, 0, 125, 101, 19, 133, 49,
+ 3, 219, 225, 59, 21, 39, 113, 252, 205, 39, 26, 14, 51, 144, 47,
+ 246, 53, 40, 35, 144, 221, 139, 19, 96, 56, 204, 136, 8, 25, 80,
+ 111, 164, 139, 93, 128, 225, 48, 3, 249, 170, 253, 206, 35, 43, 67,
+ 238, 111, 56, 204, 64, 187, 235, 139, 25, 114, 237, 9, 218, 88, 95,
+ 204, 144, 252, 236, 2, 244, 199, 12, 201, 15, 218, 78, 95, 204, 144,
+ 185, 25, 196, 9, 190, 35, 222, 15, 248, 65, 160, 16, 102, 28, 185,
+ 59, 56, 38, 128, 120, 62, 94, 24, 51, 176, 29, 30, 3, 38, 112,
+ 252, 115, 198, 233, 135, 25, 114, 126, 78, 17, 50, 228, 224, 157, 228,
+ 172, 28, 159, 113, 250, 97, 134, 156, 159, 67, 190, 88, 15, 64, 35,
+ 93, 138, 252, 244, 195, 12, 57, 63, 167, 198, 171, 99, 6, 202, 84,
+ 114, 243, 211, 15, 51, 104, 126, 238, 194, 218, 29, 255, 94, 209, 88,
+ 177, 124, 212, 215, 230, 127, 204, 207, 115, 228, 215, 165, 73, 71, 214,
+ 107, 157, 155, 170, 213, 160, 8, 126, 121, 99, 196, 242, 129, 30, 213,
+ 255, 152, 235, 74, 78, 93, 151, 118, 251, 172, 27, 63, 104, 79, 188,
+ 183, 118, 128, 88, 158, 22, 93, 226, 90, 118, 222, 40, 187, 112, 93,
+ 186, 188, 118, 180, 214, 121, 163, 218, 222, 90, 130, 31, 5, 222, 207,
+ 57, 42, 242, 143, 57, 152, 2, 188, 95, 24, 53, 75, 235, 28, 76,
+ 237, 142, 120, 63, 98, 15, 70, 77, 224, 7, 254, 66, 152, 233, 204,
+ 157, 233, 247, 13, 22, 123, 54, 18, 198, 12, 108, 135, 253, 192, 151,
+ 227, 31, 111, 165, 43, 102, 106, 104, 244, 131, 149, 177, 18, 28, 159,
+ 69, 132, 12, 153, 15, 192, 62, 43, 39, 167, 142, 174, 152, 209, 44,
+ 163, 105, 159, 100, 110, 12, 240, 33, 214, 198, 128, 222, 72, 23, 243,
+ 90, 186, 98, 70, 179, 140, 134, 146, 71, 120, 44, 131, 124, 213, 238,
+ 136, 247, 97, 177, 223, 78, 87, 204, 104, 150, 17, 248, 75, 53, 206,
+ 44, 48, 81, 217, 221, 90, 217, 82, 245, 27, 220, 208, 142, 136, 31,
+ 162, 123, 165, 196, 80, 220, 115, 240, 127, 170, 137, 68, 173, 69, 45,
+ 69, 206, 224, 15, 197, 221, 103, 3, 75, 168, 154, 45, 27, 226, 125,
+ 155, 237, 219, 183, 81, 182, 31, 150, 231, 75, 167, 244, 179, 199, 99,
+ 212, 96, 145, 181, 40, 0, 244, 155, 71, 244, 253, 89, 59, 142, 94,
+ 48, 216, 129, 187, 135, 148, 197, 170, 105, 201, 62, 250, 150, 251, 58,
+ 222, 58, 82, 169, 201, 33, 218, 249, 202, 14, 182, 77, 6, 221, 100,
+ 208, 126, 182, 30, 150, 73, 27, 221, 61, 138, 251, 166, 128, 62, 233,
+ 162, 246, 162, 12, 240, 135, 207, 190, 154, 156, 161, 205, 162, 206, 178,
+ 109, 46, 210, 131, 91, 252, 79, 73, 27, 69, 92, 166, 63, 127, 185,
+ 137, 251, 102, 129, 62, 167, 68, 182, 162, 115, 224, 15, 245, 253, 21,
+ 117, 141, 190, 58, 0, 221, 145, 154, 67, 239, 217, 125, 95, 73, 27,
+ 71, 220, 164, 23, 138, 30, 243, 214, 95, 126, 71, 229, 210, 39, 115,
+ 10, 216, 54, 121, 244, 251, 137, 133, 108, 223, 123, 116, 83, 163, 247,
+ 184, 239, 101, 81, 7, 209, 255, 192, 95, 14, 248, 195, 250, 70, 61,
+ 160, 235, 0, 44, 168, 90, 40, 104, 227, 89, 95, 149, 180, 121, 196,
+ 19, 250, 201, 235, 79, 184, 239, 77, 16, 55, 110, 129, 126, 183, 137,
+ 190, 38, 209, 5, 116, 114, 255, 103, 108, 155, 151, 244, 167, 181, 119,
+ 85, 182, 138, 40, 164, 37, 247, 255, 135, 251, 230, 129, 62, 247, 128,
+ 174, 247, 9, 125, 139, 163, 222, 210, 75, 219, 160, 122, 93, 17, 93,
+ 241, 247, 97, 37, 93, 26, 254, 145, 254, 231, 214, 94, 220, 247, 17,
+ 176, 213, 99, 240, 247, 148, 248, 70, 197, 81, 95, 232, 216, 103, 137,
+ 108, 155, 239, 116, 241, 240, 4, 182, 111, 49, 189, 228, 250, 42, 220,
+ 183, 0, 244, 121, 1, 254, 94, 129, 111, 140, 250, 254, 136, 42, 165,
+ 15, 245, 194, 181, 68, 102, 217, 213, 88, 21, 45, 53, 98, 2, 61,
+ 23, 224, 190, 111, 64, 159, 119, 224, 175, 136, 232, 251, 91, 110, 204,
+ 220, 190, 182, 136, 109, 99, 202, 220, 14, 88, 204, 126, 223, 138, 204,
+ 237, 205, 92, 125, 242, 35, 232, 243, 25, 252, 125, 39, 250, 254, 138,
+ 170, 204, 84, 183, 64, 109, 170, 49, 237, 130, 150, 176, 223, 168, 58,
+ 211, 231, 52, 215, 183, 20, 246, 49, 178, 17, 85, 48, 34, 251, 214,
+ 100, 184, 26, 176, 5, 166, 51, 62, 213, 101, 200, 218, 112, 21, 208,
+ 167, 58, 248, 171, 69, 244, 69, 184, 132, 177, 10, 225, 18, 238, 41,
+ 135, 177, 7, 225, 18, 209, 238, 0, 151, 220, 115, 205, 184, 84, 0,
+ 92, 238, 23, 87, 192, 184, 244, 15, 59, 164, 108, 63, 28, 224, 50,
+ 248, 57, 63, 46, 107, 90, 196, 209, 59, 119, 55, 196, 184, 68, 99,
+ 94, 21, 128, 203, 106, 11, 248, 113, 249, 11, 224, 242, 249, 200, 61,
+ 24, 151, 155, 163, 50, 48, 46, 7, 239, 190, 160, 1, 151, 132, 175,
+ 1, 92, 86, 140, 191, 135, 113, 105, 122, 237, 165, 138, 6, 184, 156,
+ 255, 250, 61, 129, 75, 91, 128, 203, 14, 0, 151, 36, 62, 174, 209,
+ 183, 107, 124, 199, 184, 28, 94, 90, 202, 126, 243, 155, 116, 208, 23,
+ 35, 222, 154, 170, 81, 116, 46, 61, 98, 141, 169, 27, 194, 229, 233,
+ 87, 98, 37, 109, 10, 112, 105, 79, 85, 117, 227, 112, 105, 7, 112,
+ 105, 7, 112, 105, 79, 248, 248, 3, 186, 210, 236, 218, 110, 8, 151,
+ 191, 247, 212, 84, 210, 205, 33, 46, 243, 107, 184, 113, 184, 180, 7,
+ 184, 180, 7, 184, 228, 250, 26, 3, 92, 230, 47, 68, 181, 220, 151,
+ 116, 71, 107, 213, 251, 255, 12, 47, 164, 79, 185, 189, 34, 112, 105,
+ 7, 112, 217, 1, 224, 146, 211, 183, 0, 224, 114, 158, 243, 45, 140,
+ 75, 207, 190, 215, 84, 247, 173, 3, 92, 46, 30, 121, 158, 192, 165,
+ 45, 192, 165, 45, 192, 165, 45, 97, 171, 47, 116, 103, 219, 203, 24,
+ 151, 157, 141, 174, 178, 62, 94, 76, 59, 222, 186, 70, 224, 210, 22,
+ 224, 210, 22, 224, 146, 236, 91, 74, 111, 250, 245, 31, 198, 229, 158,
+ 41, 42, 218, 24, 224, 50, 227, 225, 77, 2, 151, 182, 0, 151, 182,
+ 0, 151, 92, 95, 209, 41, 99, 198, 102, 197, 85, 140, 203, 71, 54,
+ 23, 216, 56, 84, 145, 233, 52, 41, 147, 192, 165, 45, 192, 165, 45,
+ 192, 37, 17, 179, 1, 46, 99, 20, 123, 48, 46, 59, 157, 221, 166,
+ 170, 123, 135, 87, 103, 138, 119, 175, 35, 112, 9, 124, 209, 168, 29,
+ 192, 101, 59, 53, 92, 114, 235, 18, 22, 152, 134, 184, 36, 215, 43,
+ 248, 112, 9, 199, 119, 132, 203, 165, 0, 151, 112, 188, 70, 184, 68,
+ 244, 82, 128, 75, 238, 185, 102, 92, 54, 255, 171, 132, 170, 215, 245,
+ 50, 198, 229, 95, 45, 95, 43, 219, 223, 190, 231, 75, 47, 121, 215,
+ 196, 149, 195, 101, 11, 22, 151, 109, 112, 223, 39, 117, 226, 232, 85,
+ 247, 141, 240, 30, 127, 148, 59, 206, 5, 184, 52, 63, 26, 197, 187,
+ 230, 80, 223, 244, 16, 221, 244, 244, 90, 55, 132, 75, 171, 129, 59,
+ 149, 116, 5, 128, 203, 224, 251, 169, 110, 28, 46, 93, 1, 46, 41,
+ 128, 75, 6, 247, 189, 15, 112, 121, 211, 237, 172, 27, 194, 165, 115,
+ 227, 155, 74, 250, 109, 248, 101, 122, 169, 217, 93, 55, 14, 151, 61,
+ 1, 46, 61, 0, 46, 123, 115, 249, 1, 192, 101, 106, 245, 199, 110,
+ 8, 151, 119, 255, 123, 174, 164, 63, 134, 223, 164, 183, 110, 252, 127,
+ 180, 93, 7, 124, 84, 197, 243, 191, 132, 64, 32, 8, 4, 136, 244,
+ 18, 58, 136, 98, 128, 159, 10, 36, 228, 238, 61, 154, 74, 11, 130,
+ 34, 61, 180, 208, 67, 232, 45, 229, 146, 208, 107, 64, 20, 148, 22,
+ 21, 165, 9, 134, 38, 144, 220, 133, 208, 164, 67, 168, 210, 57, 122,
+ 145, 18, 122, 11, 240, 159, 121, 239, 109, 185, 112, 217, 119, 126, 242,
+ 254, 124, 62, 249, 56, 159, 231, 238, 204, 219, 185, 249, 206, 236, 206,
+ 238, 188, 189, 35, 196, 101, 105, 192, 229, 183, 7, 31, 80, 92, 30,
+ 186, 249, 76, 161, 75, 3, 46, 247, 121, 189, 225, 112, 217, 28, 112,
+ 217, 18, 112, 217, 138, 246, 221, 5, 184, 76, 168, 154, 135, 220, 143,
+ 45, 85, 88, 165, 214, 49, 196, 199, 92, 150, 238, 215, 202, 101, 102,
+ 184, 12, 1, 92, 134, 0, 46, 91, 211, 190, 53, 1, 151, 141, 234,
+ 63, 160, 184, 204, 29, 173, 126, 215, 227, 15, 192, 229, 252, 29, 255,
+ 4, 51, 92, 182, 0, 92, 126, 9, 184, 252, 156, 221, 177, 110, 189,
+ 43, 21, 106, 188, 43, 152, 224, 178, 241, 208, 52, 133, 182, 3, 46,
+ 135, 254, 154, 18, 204, 112, 217, 4, 112, 217, 24, 112, 217, 136, 225,
+ 35, 238, 137, 212, 33, 104, 123, 48, 193, 101, 239, 3, 42, 159, 2,
+ 128, 203, 241, 157, 247, 6, 51, 92, 54, 1, 92, 54, 1, 92, 54,
+ 101, 191, 17, 224, 178, 233, 230, 35, 193, 52, 94, 102, 166, 43, 116,
+ 77, 192, 229, 54, 75, 122, 48, 195, 101, 51, 192, 101, 51, 192, 101,
+ 51, 218, 183, 24, 224, 242, 233, 235, 191, 131, 9, 46, 125, 235, 170,
+ 239, 92, 18, 112, 185, 111, 193, 186, 96, 134, 203, 38, 128, 203, 198,
+ 128, 75, 102, 27, 187, 1, 151, 233, 161, 139, 130, 9, 46, 127, 25,
+ 48, 91, 161, 247, 2, 46, 167, 143, 158, 16, 204, 112, 105, 6, 92,
+ 54, 4, 92, 6, 178, 239, 186, 0, 46, 217, 94, 153, 31, 165, 237,
+ 128, 75, 126, 15, 205, 199, 163, 62, 224, 178, 62, 224, 178, 254, 59,
+ 184, 196, 57, 49, 63, 143, 197, 57, 46, 193, 37, 161, 45, 128, 75,
+ 246, 156, 224, 114, 20, 224, 114, 20, 229, 183, 19, 226, 101, 155, 8,
+ 43, 173, 59, 105, 168, 181, 175, 15, 241, 242, 84, 105, 214, 183, 45,
+ 244, 233, 3, 127, 227, 184, 190, 149, 32, 94, 14, 92, 16, 77, 235,
+ 78, 200, 26, 172, 4, 224, 114, 72, 248, 72, 225, 62, 88, 65, 192,
+ 101, 222, 46, 195, 204, 4, 151, 221, 102, 170, 223, 112, 43, 10, 184,
+ 252, 117, 235, 32, 51, 195, 229, 48, 192, 229, 80, 192, 229, 16, 118,
+ 199, 161, 215, 14, 41, 224, 167, 126, 102, 130, 203, 83, 1, 97, 234,
+ 62, 24, 196, 203, 234, 145, 189, 204, 12, 151, 17, 128, 203, 193, 128,
+ 203, 112, 46, 110, 29, 148, 126, 49, 247, 48, 19, 92, 46, 248, 41,
+ 84, 165, 33, 94, 206, 123, 34, 254, 254, 75, 65, 192, 101, 158, 176,
+ 46, 102, 130, 203, 50, 195, 58, 153, 213, 185, 232, 25, 169, 180, 181,
+ 131, 153, 225, 114, 16, 224, 114, 0, 224, 114, 0, 231, 15, 206, 75,
+ 15, 210, 218, 81, 92, 90, 215, 124, 173, 208, 11, 33, 94, 154, 23,
+ 126, 195, 225, 178, 31, 224, 178, 63, 224, 178, 63, 237, 123, 55, 246,
+ 154, 52, 127, 21, 145, 123, 83, 10, 234, 208, 221, 172, 218, 218, 109,
+ 105, 88, 158, 222, 102, 134, 203, 129, 128, 203, 65, 128, 203, 193, 180,
+ 239, 50, 136, 151, 177, 3, 136, 174, 50, 164, 33, 182, 254, 10, 253,
+ 47, 224, 178, 90, 129, 129, 102, 134, 203, 8, 192, 101, 4, 224, 114,
+ 136, 83, 188, 188, 185, 186, 191, 153, 224, 114, 203, 19, 149, 143, 23,
+ 224, 114, 74, 195, 126, 102, 134, 203, 8, 192, 101, 4, 224, 50, 130,
+ 179, 241, 215, 210, 132, 222, 125, 72, 27, 57, 102, 158, 74, 231, 3,
+ 92, 142, 221, 75, 159, 3, 46, 7, 3, 46, 7, 3, 46, 217, 59,
+ 123, 0, 46, 123, 60, 35, 252, 189, 228, 167, 29, 6, 152, 201, 60,
+ 182, 98, 121, 118, 62, 236, 33, 200, 123, 12, 239, 251, 156, 123, 231,
+ 199, 128, 203, 224, 252, 100, 127, 245, 61, 185, 146, 143, 250, 205, 192,
+ 23, 128, 203, 23, 121, 153, 77, 190, 6, 187, 242, 240, 24, 6, 184,
+ 28, 206, 141, 183, 176, 204, 246, 111, 253, 40, 189, 5, 112, 201, 239,
+ 235, 250, 120, 140, 0, 92, 142, 0, 92, 142, 120, 247, 140, 122, 97,
+ 174, 30, 182, 6, 172, 91, 123, 232, 229, 20, 234, 177, 243, 211, 208,
+ 55, 180, 166, 126, 78, 1, 219, 209, 179, 221, 190, 92, 13, 249, 7,
+ 198, 229, 174, 145, 47, 187, 63, 5, 198, 84, 88, 203, 95, 125, 96,
+ 92, 238, 26, 249, 178, 251, 83, 6, 122, 147, 177, 248, 126, 96, 92,
+ 238, 58, 180, 102, 150, 26, 242, 154, 90, 14, 190, 134, 113, 185, 107,
+ 212, 187, 145, 251, 61, 214, 15, 140, 221, 239, 241, 253, 192, 216, 253,
+ 30, 212, 157, 145, 251, 61, 136, 19, 250, 125, 159, 202, 96, 7, 133,
+ 245, 48, 83, 159, 213, 182, 85, 31, 232, 237, 95, 77, 31, 51, 216,
+ 142, 214, 15, 86, 231, 190, 239, 83, 213, 56, 204, 248, 115, 50, 18,
+ 225, 157, 18, 53, 57, 150, 170, 198, 97, 6, 249, 210, 113, 0, 77,
+ 198, 146, 94, 197, 56, 204, 248, 87, 203, 82, 63, 88, 77, 203, 195,
+ 85, 49, 14, 51, 168, 119, 35, 247, 123, 44, 85, 141, 221, 239, 65,
+ 125, 26, 185, 223, 19, 90, 197, 216, 253, 30, 196, 9, 189, 63, 197,
+ 31, 236, 160, 134, 14, 102, 106, 7, 112, 119, 123, 12, 244, 118, 84,
+ 212, 199, 12, 182, 99, 247, 142, 48, 254, 17, 21, 141, 195, 12, 242,
+ 165, 49, 0, 104, 148, 169, 52, 170, 104, 28, 102, 66, 57, 25, 56,
+ 110, 50, 150, 132, 10, 198, 97, 6, 249, 58, 125, 223, 71, 147, 225,
+ 95, 193, 56, 204, 160, 222, 141, 140, 51, 166, 138, 198, 198, 25, 212,
+ 167, 145, 113, 198, 191, 130, 177, 113, 6, 113, 66, 207, 48, 135, 12,
+ 242, 118, 84, 214, 195, 12, 59, 195, 156, 224, 24, 232, 29, 146, 161,
+ 143, 25, 108, 71, 237, 57, 129, 251, 237, 143, 24, 135, 25, 228, 75,
+ 107, 161, 224, 157, 80, 166, 242, 142, 233, 198, 97, 6, 249, 210, 253,
+ 30, 160, 201, 88, 2, 252, 251, 27, 134, 153, 144, 140, 44, 181, 80,
+ 25, 154, 140, 128, 1, 198, 157, 95, 59, 98, 108, 156, 65, 29, 27,
+ 122, 174, 192, 191, 191, 161, 113, 6, 117, 103, 100, 156, 65, 156, 208,
+ 250, 193, 208, 65, 222, 136, 33, 49, 102, 216, 153, 79, 135, 47, 244,
+ 173, 61, 72, 23, 51, 216, 142, 98, 6, 104, 194, 63, 49, 96, 144,
+ 113, 152, 225, 100, 36, 192, 59, 57, 52, 57, 1, 2, 25, 255, 21,
+ 51, 200, 151, 214, 245, 2, 77, 198, 146, 216, 125, 144, 97, 152, 241,
+ 229, 100, 152, 52, 153, 202, 56, 68, 50, 254, 35, 102, 80, 239, 70,
+ 198, 153, 128, 44, 252, 114, 26, 103, 80, 159, 70, 198, 153, 128, 44,
+ 252, 114, 26, 103, 16, 39, 52, 206, 56, 6, 121, 35, 134, 178, 193,
+ 12, 86, 152, 105, 60, 180, 12, 28, 244, 245, 175, 224, 10, 51, 30,
+ 78, 152, 193, 118, 116, 29, 80, 145, 241, 15, 77, 207, 222, 14, 138,
+ 172, 241, 72, 253, 37, 181, 68, 144, 168, 86, 230, 80, 241, 105, 236,
+ 123, 40, 21, 153, 140, 68, 120, 39, 148, 169, 52, 250, 51, 123, 25,
+ 173, 242, 122, 167, 174, 184, 149, 55, 72, 84, 43, 243, 221, 39, 83,
+ 217, 119, 17, 43, 112, 227, 0, 154, 140, 197, 177, 58, 123, 25, 123,
+ 90, 28, 176, 45, 73, 206, 45, 172, 149, 185, 115, 129, 157, 197, 241,
+ 175, 224, 140, 25, 148, 169, 156, 201, 249, 35, 123, 25, 151, 190, 250,
+ 218, 252, 112, 136, 184, 86, 102, 253, 94, 86, 43, 131, 122, 231, 235,
+ 3, 80, 143, 132, 31, 161, 177, 86, 134, 61, 199, 188, 104, 5, 211,
+ 50, 83, 121, 211, 42, 248, 227, 107, 101, 186, 70, 38, 211, 239, 158,
+ 147, 246, 88, 43, 243, 120, 112, 140, 93, 175, 78, 100, 239, 159, 1,
+ 118, 82, 31, 240, 126, 241, 220, 118, 82, 31, 96, 46, 144, 110, 211,
+ 171, 15, 40, 63, 32, 214, 70, 234, 3, 8, 141, 245, 1, 236, 185,
+ 184, 70, 2, 237, 130, 215, 1, 254, 206, 68, 7, 132, 198, 90, 25,
+ 246, 220, 181, 14, 176, 86, 102, 119, 237, 109, 84, 7, 164, 61, 214,
+ 202, 76, 206, 51, 86, 87, 7, 63, 252, 94, 158, 234, 160, 230, 135,
+ 39, 109, 68, 7, 1, 197, 18, 116, 117, 240, 219, 163, 21, 41, 68,
+ 7, 132, 198, 58, 17, 246, 92, 172, 3, 180, 91, 190, 86, 6, 237,
+ 144, 232, 128, 208, 88, 43, 195, 158, 163, 14, 106, 129, 14, 62, 5,
+ 29, 124, 230, 84, 43, 19, 211, 132, 213, 202, 144, 246, 88, 43, 83,
+ 113, 163, 126, 173, 76, 151, 30, 172, 86, 230, 207, 243, 172, 86, 38,
+ 178, 142, 126, 173, 204, 237, 174, 9, 180, 86, 134, 208, 168, 3, 246,
+ 92, 172, 3, 196, 21, 111, 7, 136, 19, 162, 3, 66, 99, 173, 12,
+ 123, 142, 58, 24, 12, 58, 24, 4, 58, 24, 228, 84, 43, 147, 121,
+ 150, 213, 202, 144, 246, 88, 43, 19, 255, 92, 191, 86, 102, 247, 48,
+ 86, 43, 83, 234, 33, 171, 149, 201, 204, 208, 175, 149, 185, 241, 148,
+ 213, 202, 16, 26, 177, 192, 158, 235, 204, 155, 28, 44, 6, 88, 151,
+ 15, 242, 78, 10, 21, 198, 0, 167, 122, 73, 11, 232, 47, 109, 165,
+ 126, 12, 192, 118, 244, 172, 228, 42, 198, 63, 100, 165, 187, 49, 192,
+ 245, 92, 0, 241, 78, 207, 74, 174, 98, 50, 44, 64, 91, 52, 159,
+ 233, 88, 225, 110, 12, 112, 45, 3, 241, 68, 199, 193, 201, 192, 113,
+ 147, 177, 68, 172, 112, 55, 6, 184, 150, 129, 246, 74, 199, 177, 210,
+ 57, 6, 88, 136, 190, 86, 184, 27, 3, 92, 203, 64, 123, 160, 231,
+ 254, 87, 14, 114, 170, 29, 97, 126, 211, 106, 38, 52, 214, 142, 136,
+ 252, 169, 211, 185, 255, 21, 206, 252, 152, 15, 178, 154, 9, 141, 181,
+ 45, 34, 223, 228, 116, 238, 63, 11, 63, 134, 103, 171, 153, 208, 200,
+ 79, 132, 115, 167, 252, 65, 22, 126, 12, 27, 86, 51, 161, 113, 188,
+ 34, 204, 56, 157, 251, 95, 206, 48, 99, 89, 10, 243, 38, 135, 30,
+ 102, 216, 90, 195, 4, 125, 173, 191, 235, 99, 6, 219, 209, 179, 146,
+ 203, 24, 127, 223, 223, 141, 195, 12, 242, 165, 182, 134, 50, 150, 107,
+ 235, 128, 223, 140, 195, 140, 137, 147, 129, 227, 38, 99, 9, 248, 205,
+ 56, 204, 32, 95, 167, 115, 255, 154, 140, 180, 165, 198, 97, 6, 245,
+ 206, 207, 189, 93, 97, 6, 231, 222, 238, 98, 6, 117, 204, 243, 115,
+ 133, 25, 92, 107, 184, 139, 153, 128, 44, 252, 92, 97, 6, 215, 26,
+ 238, 98, 6, 117, 199, 243, 115, 133, 25, 28, 175, 187, 152, 65, 156,
+ 208, 60, 240, 86, 176, 131, 229, 122, 152, 97, 245, 101, 105, 191, 130,
+ 63, 255, 69, 31, 51, 216, 142, 198, 128, 95, 25, 255, 244, 159, 141,
+ 195, 140, 133, 147, 145, 6, 239, 148, 166, 201, 9, 253, 217, 56, 204,
+ 32, 95, 58, 14, 160, 201, 88, 50, 18, 141, 195, 140, 229, 23, 103,
+ 204, 160, 76, 133, 91, 162, 113, 152, 65, 189, 231, 20, 51, 78, 123,
+ 19, 63, 231, 28, 51, 60, 63, 212, 103, 78, 49, 195, 243, 179, 38,
+ 230, 28, 51, 252, 220, 12, 113, 66, 239, 70, 72, 1, 59, 88, 170,
+ 135, 25, 86, 95, 230, 15, 125, 19, 237, 250, 152, 193, 118, 116, 237,
+ 156, 202, 248, 7, 216, 115, 134, 25, 126, 125, 142, 124, 233, 218, 25,
+ 104, 148, 169, 216, 156, 45, 103, 152, 225, 215, 231, 254, 156, 12, 28,
+ 55, 25, 75, 136, 45, 103, 152, 225, 215, 231, 200, 215, 233, 94, 50,
+ 77, 134, 35, 37, 103, 152, 33, 235, 243, 32, 77, 239, 196, 134, 38,
+ 119, 243, 78, 219, 62, 188, 194, 59, 235, 115, 172, 149, 105, 184, 243,
+ 135, 108, 215, 166, 78, 126, 220, 198, 248, 125, 11, 252, 62, 242, 40,
+ 243, 206, 90, 55, 3, 248, 117, 176, 184, 199, 47, 132, 227, 103, 105,
+ 237, 157, 22, 254, 236, 117, 195, 172, 235, 70, 203, 238, 195, 102, 255,
+ 188, 113, 217, 174, 27, 157, 230, 142, 41, 140, 95, 72, 87, 239, 180,
+ 203, 221, 99, 222, 89, 131, 165, 111, 59, 108, 62, 210, 120, 100, 182,
+ 107, 48, 62, 206, 32, 78, 40, 102, 214, 130, 29, 108, 213, 195, 12,
+ 171, 47, 115, 36, 15, 242, 14, 221, 162, 143, 25, 108, 71, 243, 192,
+ 201, 92, 30, 120, 163, 187, 152, 113, 93, 255, 241, 119, 80, 179, 100,
+ 154, 7, 230, 100, 56, 224, 157, 28, 154, 28, 199, 90, 119, 49, 227,
+ 90, 198, 163, 238, 54, 42, 3, 249, 210, 113, 0, 77, 198, 146, 246,
+ 183, 187, 152, 113, 45, 35, 239, 252, 43, 108, 79, 115, 139, 51, 102,
+ 80, 166, 66, 236, 112, 23, 51, 174, 101, 124, 205, 213, 202, 160, 222,
+ 249, 51, 134, 168, 71, 194, 143, 208, 88, 43, 195, 158, 147, 51, 134,
+ 149, 77, 129, 240, 199, 215, 202, 172, 182, 149, 160, 223, 121, 95, 115,
+ 89, 109, 143, 181, 50, 47, 182, 212, 182, 57, 159, 201, 175, 108, 26,
+ 103, 170, 196, 214, 226, 69, 103, 73, 213, 143, 126, 76, 191, 243, 78,
+ 176, 154, 59, 243, 15, 169, 103, 187, 239, 133, 121, 36, 172, 149, 169,
+ 223, 151, 124, 139, 105, 179, 244, 195, 185, 53, 118, 114, 38, 255, 73,
+ 72, 178, 157, 157, 49, 44, 103, 218, 0, 127, 155, 77, 101, 157, 106,
+ 101, 50, 143, 236, 177, 147, 51, 134, 126, 187, 142, 217, 213, 51, 104,
+ 251, 164, 69, 193, 167, 237, 236, 140, 97, 89, 211, 54, 83, 25, 211,
+ 46, 248, 227, 107, 101, 166, 246, 184, 104, 39, 103, 12, 115, 127, 117,
+ 213, 78, 206, 228, 199, 72, 183, 132, 249, 43, 172, 149, 169, 240, 215,
+ 61, 59, 57, 99, 184, 250, 224, 35, 187, 122, 70, 253, 140, 20, 120,
+ 237, 185, 157, 157, 49, 44, 109, 58, 4, 127, 233, 240, 199, 206, 138,
+ 159, 151, 58, 174, 246, 72, 37, 103, 12, 151, 109, 52, 41, 116, 161,
+ 232, 203, 146, 99, 220, 91, 59, 59, 99, 88, 218, 116, 28, 254, 78,
+ 114, 125, 189, 226, 174, 73, 181, 223, 102, 216, 201, 25, 195, 202, 91,
+ 174, 171, 122, 142, 190, 45, 61, 24, 122, 206, 206, 206, 24, 150, 54,
+ 157, 129, 177, 158, 227, 198, 107, 138, 187, 43, 141, 26, 113, 200, 78,
+ 206, 24, 250, 23, 221, 161, 141, 247, 161, 180, 43, 105, 147, 157, 157,
+ 49, 44, 99, 186, 4, 250, 186, 194, 233, 249, 69, 236, 19, 105, 189,
+ 99, 185, 157, 156, 49, 60, 127, 101, 177, 93, 173, 5, 120, 41, 125,
+ 118, 99, 174, 157, 157, 49, 44, 103, 186, 1, 127, 183, 184, 223, 247,
+ 73, 236, 107, 41, 127, 171, 41, 164, 141, 124, 161, 206, 4, 133, 126,
+ 27, 236, 33, 239, 46, 30, 107, 103, 103, 12, 203, 155, 238, 193, 95,
+ 6, 215, 23, 107, 101, 206, 245, 140, 183, 147, 51, 134, 251, 28, 241,
+ 154, 158, 243, 200, 191, 159, 25, 111, 103, 103, 12, 203, 155, 30, 195,
+ 223, 115, 174, 47, 214, 202, 124, 92, 101, 146, 157, 156, 49, 236, 222,
+ 114, 178, 54, 222, 130, 242, 119, 35, 232, 251, 152, 94, 99, 31, 143,
+ 242, 166, 220, 30, 229, 157, 206, 228, 179, 28, 176, 31, 165, 241, 76,
+ 62, 159, 27, 246, 129, 62, 5, 225, 175, 8, 215, 151, 224, 18, 125,
+ 21, 95, 43, 131, 190, 135, 224, 146, 208, 205, 0, 151, 236, 185, 107,
+ 92, 94, 6, 92, 46, 190, 146, 151, 226, 50, 79, 17, 187, 210, 190,
+ 61, 224, 50, 111, 141, 122, 66, 92, 230, 242, 155, 37, 53, 235, 254,
+ 1, 197, 37, 137, 121, 222, 128, 203, 122, 233, 115, 133, 184, 196, 90,
+ 153, 74, 35, 151, 82, 92, 38, 167, 39, 81, 92, 182, 173, 105, 23,
+ 226, 242, 21, 224, 50, 96, 197, 1, 138, 203, 138, 205, 78, 81, 92,
+ 22, 47, 118, 65, 136, 75, 172, 149, 249, 96, 243, 85, 138, 203, 181,
+ 241, 183, 40, 46, 63, 105, 125, 79, 136, 75, 172, 149, 241, 254, 224,
+ 33, 197, 229, 228, 143, 158, 107, 248, 56, 35, 149, 168, 253, 70, 136,
+ 75, 172, 149, 169, 153, 199, 155, 226, 114, 246, 184, 220, 10, 93, 22,
+ 112, 121, 43, 35, 87, 42, 195, 101, 41, 192, 101, 41, 192, 101, 41,
+ 167, 90, 153, 221, 205, 31, 80, 92, 118, 254, 253, 138, 66, 103, 70,
+ 221, 150, 94, 153, 78, 10, 113, 121, 59, 246, 174, 148, 252, 114, 59,
+ 197, 229, 254, 7, 41, 234, 125, 54, 81, 15, 165, 218, 183, 54, 112,
+ 184, 44, 251, 14, 46, 241, 236, 239, 212, 94, 127, 81, 92, 166, 123,
+ 108, 210, 240, 241, 82, 42, 182, 100, 19, 135, 203, 178, 128, 203, 178,
+ 128, 203, 178, 156, 141, 191, 150, 102, 21, 182, 81, 92, 134, 15, 85,
+ 229, 98, 173, 76, 203, 99, 201, 28, 46, 203, 2, 46, 203, 2, 46,
+ 203, 58, 213, 202, 36, 236, 221, 72, 113, 25, 90, 108, 29, 197, 101,
+ 230, 159, 43, 57, 92, 150, 5, 92, 150, 3, 92, 150, 227, 222, 57,
+ 159, 188, 172, 227, 18, 138, 203, 42, 199, 231, 83, 92, 46, 111, 57,
+ 135, 195, 37, 244, 241, 40, 247, 14, 46, 217, 190, 132, 31, 165, 17,
+ 151, 252, 126, 133, 8, 151, 24, 223, 9, 46, 167, 0, 46, 49, 94,
+ 19, 92, 18, 26, 107, 101, 216, 115, 196, 101, 21, 192, 101, 21, 192,
+ 101, 21, 202, 175, 114, 155, 76, 203, 121, 243, 1, 90, 43, 243, 79,
+ 244, 85, 165, 253, 137, 51, 221, 165, 132, 207, 249, 90, 153, 138, 128,
+ 203, 42, 128, 203, 106, 180, 239, 137, 247, 103, 73, 31, 205, 243, 164,
+ 181, 50, 100, 238, 56, 10, 112, 153, 184, 42, 86, 184, 231, 80, 214,
+ 107, 189, 180, 104, 0, 171, 149, 105, 115, 243, 23, 133, 206, 11, 184,
+ 28, 218, 155, 175, 149, 105, 0, 184, 12, 2, 92, 6, 211, 190, 167,
+ 1, 151, 126, 119, 118, 208, 90, 153, 181, 41, 106, 77, 198, 157, 168,
+ 125, 82, 145, 95, 79, 113, 181, 50, 18, 224, 178, 17, 224, 178, 137,
+ 83, 173, 204, 184, 241, 14, 90, 43, 115, 225, 83, 181, 86, 230, 81,
+ 212, 81, 233, 202, 205, 127, 133, 123, 29, 101, 1, 151, 183, 61, 88,
+ 173, 204, 197, 210, 106, 173, 76, 25, 192, 101, 183, 79, 95, 115, 181,
+ 50, 205, 0, 151, 95, 0, 46, 191, 164, 125, 83, 0, 151, 211, 55,
+ 229, 166, 103, 242, 147, 6, 168, 181, 50, 93, 98, 46, 75, 114, 121,
+ 190, 86, 166, 5, 224, 178, 57, 224, 178, 57, 237, 91, 3, 112, 249,
+ 83, 249, 135, 180, 86, 102, 191, 183, 250, 206, 155, 1, 151, 115, 50,
+ 78, 115, 181, 50, 159, 3, 46, 155, 2, 46, 27, 211, 190, 151, 172,
+ 119, 37, 105, 206, 30, 90, 43, 19, 24, 177, 67, 171, 179, 121, 40,
+ 213, 106, 147, 202, 213, 202, 200, 128, 75, 9, 112, 105, 225, 206, 213,
+ 63, 145, 66, 95, 176, 90, 153, 47, 122, 176, 90, 153, 122, 251, 119,
+ 115, 181, 50, 18, 224, 82, 2, 92, 202, 220, 217, 248, 215, 82, 174,
+ 101, 135, 104, 173, 204, 253, 250, 7, 21, 186, 22, 224, 114, 245, 129,
+ 253, 92, 173, 76, 35, 192, 165, 12, 184, 100, 125, 125, 1, 151, 159,
+ 214, 218, 78, 107, 101, 30, 199, 171, 53, 61, 62, 128, 203, 239, 107,
+ 173, 225, 106, 101, 36, 192, 165, 5, 112, 201, 108, 227, 32, 224, 114,
+ 215, 177, 159, 104, 173, 76, 133, 181, 179, 20, 250, 72, 84, 65, 185,
+ 110, 194, 120, 174, 86, 38, 16, 112, 89, 31, 112, 89, 143, 155, 31,
+ 20, 150, 217, 94, 153, 31, 165, 177, 86, 134, 223, 67, 243, 241, 248,
+ 20, 112, 249, 41, 224, 242, 211, 119, 112, 137, 115, 98, 126, 30, 251,
+ 53, 87, 43, 243, 53, 87, 43, 243, 245, 59, 181, 50, 17, 240, 70,
+ 17, 78, 181, 50, 23, 135, 176, 90, 153, 175, 180, 246, 245, 32, 94,
+ 94, 47, 193, 215, 202, 68, 0, 46, 35, 0, 151, 172, 111, 5, 136,
+ 151, 249, 35, 89, 173, 12, 89, 131, 21, 7, 92, 30, 28, 58, 82,
+ 184, 15, 134, 181, 50, 3, 70, 178, 90, 153, 65, 235, 88, 173, 76,
+ 151, 123, 124, 173, 204, 64, 192, 229, 0, 192, 37, 171, 59, 201, 229,
+ 181, 67, 170, 114, 136, 213, 202, 180, 30, 198, 106, 101, 46, 237, 226,
+ 107, 101, 250, 1, 46, 251, 2, 46, 251, 56, 213, 202, 108, 152, 199,
+ 106, 101, 124, 94, 135, 154, 73, 188, 236, 217, 163, 155, 48, 215, 82,
+ 8, 112, 185, 227, 18, 171, 149, 185, 244, 136, 213, 202, 220, 200, 221,
+ 145, 171, 149, 9, 3, 92, 246, 6, 92, 246, 102, 53, 188, 128, 203,
+ 99, 109, 191, 166, 184, 236, 92, 65, 173, 143, 153, 6, 241, 210, 251,
+ 62, 95, 43, 211, 19, 112, 217, 19, 112, 217, 139, 246, 125, 24, 123,
+ 77, 234, 62, 159, 213, 202, 180, 46, 174, 214, 202, 28, 1, 92, 222,
+ 252, 190, 23, 87, 43, 19, 6, 184, 236, 3, 184, 236, 75, 251, 174,
+ 133, 120, 57, 125, 87, 95, 90, 43, 243, 97, 45, 181, 246, 229, 38,
+ 224, 114, 206, 15, 3, 184, 90, 153, 126, 128, 203, 126, 128, 75, 86,
+ 163, 243, 10, 112, 233, 253, 39, 171, 149, 217, 33, 247, 167, 181, 50,
+ 214, 147, 124, 173, 76, 127, 192, 101, 63, 192, 101, 63, 167, 120, 121,
+ 173, 127, 95, 90, 43, 211, 120, 103, 95, 90, 43, 243, 91, 217, 126,
+ 92, 173, 76, 63, 192, 101, 63, 192, 101, 63, 167, 120, 57, 243, 139,
+ 1, 180, 86, 230, 220, 124, 181, 166, 231, 109, 84, 30, 121, 212, 103,
+ 131, 185, 90, 153, 254, 128, 203, 254, 128, 75, 102, 27, 79, 1, 151,
+ 211, 231, 177, 90, 153, 171, 221, 212, 90, 153, 87, 128, 203, 218, 213,
+ 249, 90, 153, 129, 128, 203, 129, 128, 203, 65, 78, 241, 146, 237, 223,
+ 250, 81, 26, 107, 101, 248, 125, 93, 31, 232, 83, 16, 254, 138, 112,
+ 125, 105, 78, 97, 45, 151, 187, 158, 5, 235, 228, 20, 189, 156, 194,
+ 103, 108, 189, 155, 4, 109, 183, 187, 145, 83, 72, 226, 214, 226, 73,
+ 140, 127, 194, 54, 227, 114, 215, 161, 156, 12, 43, 188, 147, 67, 147,
+ 227, 191, 205, 184, 220, 53, 242, 165, 235, 125, 160, 201, 88, 146, 210,
+ 140, 203, 93, 155, 182, 59, 231, 20, 80, 166, 226, 27, 211, 140, 203,
+ 93, 163, 222, 141, 220, 239, 241, 223, 102, 236, 126, 15, 234, 211, 200,
+ 253, 30, 75, 154, 177, 251, 61, 136, 19, 154, 135, 155, 6, 118, 176,
+ 86, 15, 51, 172, 190, 204, 31, 250, 38, 206, 112, 35, 119, 61, 139,
+ 203, 249, 206, 228, 114, 215, 51, 140, 195, 12, 242, 165, 185, 107, 160,
+ 81, 166, 146, 35, 155, 110, 28, 102, 252, 57, 25, 56, 110, 50, 150,
+ 144, 233, 198, 97, 6, 249, 58, 229, 174, 53, 25, 142, 105, 198, 97,
+ 6, 245, 110, 228, 126, 15, 234, 216, 200, 253, 158, 144, 233, 198, 238,
+ 247, 160, 238, 140, 220, 239, 65, 156, 208, 154, 204, 73, 96, 7, 179,
+ 244, 48, 195, 234, 203, 28, 83, 1, 99, 83, 220, 136, 51, 83, 185,
+ 56, 51, 149, 241, 207, 152, 108, 96, 156, 225, 100, 56, 224, 157, 28,
+ 154, 28, 235, 100, 227, 48, 131, 124, 233, 56, 128, 38, 99, 241, 157,
+ 108, 28, 102, 66, 167, 100, 201, 93, 79, 209, 206, 71, 76, 50, 14,
+ 51, 168, 119, 35, 227, 140, 117, 178, 177, 113, 198, 119, 178, 177, 113,
+ 6, 117, 103, 100, 156, 65, 156, 208, 154, 204, 56, 176, 131, 105, 58,
+ 152, 225, 234, 203, 18, 39, 130, 63, 159, 160, 143, 25, 108, 71, 99,
+ 192, 68, 198, 63, 105, 188, 113, 152, 241, 231, 100, 36, 194, 59, 37,
+ 106, 114, 44, 227, 141, 195, 12, 242, 165, 227, 0, 154, 140, 37, 61,
+ 222, 56, 204, 248, 79, 200, 114, 134, 121, 130, 118, 62, 34, 222, 56,
+ 204, 160, 222, 141, 140, 51, 150, 241, 198, 198, 25, 212, 167, 145, 113,
+ 38, 52, 222, 216, 56, 131, 56, 33, 152, 9, 240, 7, 59, 152, 164,
+ 135, 25, 118, 230, 51, 20, 250, 58, 172, 250, 152, 193, 118, 52, 6,
+ 196, 50, 254, 17, 86, 227, 48, 131, 124, 105, 12, 0, 26, 101, 42,
+ 243, 191, 196, 1, 134, 97, 38, 148, 147, 129, 227, 38, 99, 9, 240,
+ 31, 104, 24, 102, 144, 175, 83, 77, 166, 38, 35, 201, 223, 56, 204,
+ 160, 222, 141, 140, 51, 168, 99, 67, 207, 175, 249, 15, 52, 52, 206,
+ 160, 238, 140, 140, 51, 136, 19, 186, 158, 169, 28, 238, 237, 136, 115,
+ 129, 153, 190, 35, 6, 245, 30, 58, 98, 88, 173, 129, 189, 77, 195,
+ 121, 31, 248, 113, 184, 183, 127, 173, 112, 253, 218, 127, 104, 71, 253,
+ 51, 208, 244, 252, 90, 205, 240, 108, 237, 160, 88, 197, 49, 54, 143,
+ 37, 203, 27, 168, 152, 201, 231, 210, 14, 106, 118, 169, 193, 226, 12,
+ 39, 35, 17, 222, 41, 81, 147, 99, 173, 145, 189, 140, 69, 99, 110,
+ 216, 74, 12, 159, 159, 172, 98, 198, 181, 140, 95, 254, 153, 195, 214,
+ 76, 181, 184, 113, 0, 77, 198, 18, 80, 45, 123, 25, 11, 23, 22,
+ 218, 186, 219, 119, 191, 77, 197, 140, 107, 25, 135, 151, 109, 100, 231,
+ 125, 56, 25, 38, 77, 166, 50, 71, 171, 156, 189, 140, 55, 199, 218,
+ 154, 175, 79, 34, 152, 113, 45, 227, 199, 251, 209, 10, 102, 202, 120,
+ 170, 122, 175, 162, 180, 84, 235, 3, 80, 143, 132, 31, 161, 155, 109,
+ 152, 43, 177, 231, 38, 211, 34, 83, 101, 211, 50, 83, 21, 211, 10,
+ 110, 159, 228, 81, 171, 250, 242, 157, 61, 205, 108, 164, 62, 128, 180,
+ 207, 101, 111, 45, 47, 110, 86, 73, 24, 163, 222, 200, 237, 228, 143,
+ 251, 23, 214, 218, 124, 43, 47, 216, 252, 70, 193, 147, 167, 189, 147,
+ 124, 114, 225, 25, 97, 60, 122, 45, 135, 202, 163, 82, 227, 180, 54,
+ 189, 228, 53, 254, 179, 212, 190, 209, 97, 114, 245, 30, 243, 132, 125,
+ 223, 196, 246, 147, 171, 174, 189, 170, 181, 25, 40, 127, 120, 197, 219,
+ 166, 230, 84, 195, 229, 157, 131, 202, 138, 223, 57, 118, 136, 188, 165,
+ 36, 217, 151, 29, 46, 223, 89, 209, 88, 235, 59, 82, 46, 219, 160,
+ 141, 78, 223, 49, 114, 163, 159, 191, 177, 145, 122, 8, 203, 69, 149,
+ 246, 140, 182, 202, 13, 58, 181, 215, 233, 27, 47, 103, 206, 104, 162,
+ 181, 153, 40, 199, 167, 52, 212, 250, 78, 150, 125, 110, 125, 162, 211,
+ 119, 154, 124, 114, 211, 135, 180, 174, 136, 208, 155, 31, 37, 112, 207,
+ 179, 143, 211, 104, 47, 136, 33, 222, 94, 16, 19, 196, 94, 8, 221,
+ 20, 236, 133, 61, 71, 123, 169, 2, 246, 82, 25, 236, 133, 237, 119,
+ 63, 0, 123, 169, 55, 182, 53, 181, 23, 210, 30, 237, 101, 234, 200,
+ 5, 186, 246, 210, 192, 103, 19, 181, 151, 139, 197, 213, 253, 57, 180,
+ 151, 137, 85, 46, 217, 244, 236, 197, 179, 92, 110, 59, 177, 151, 23,
+ 149, 189, 236, 196, 94, 30, 69, 231, 210, 57, 15, 210, 79, 182, 4,
+ 220, 178, 17, 123, 73, 40, 245, 143, 166, 251, 112, 217, 225, 181, 75,
+ 215, 94, 142, 62, 249, 131, 218, 75, 253, 207, 23, 83, 123, 89, 250,
+ 211, 44, 93, 123, 105, 177, 207, 74, 237, 101, 211, 144, 209, 90, 95,
+ 171, 252, 162, 102, 152, 174, 189, 228, 13, 137, 164, 246, 146, 80, 49,
+ 142, 218, 75, 153, 178, 19, 117, 237, 229, 193, 103, 51, 168, 189, 16,
+ 26, 237, 133, 61, 23, 219, 11, 250, 67, 222, 94, 208, 191, 17, 123,
+ 33, 244, 195, 245, 115, 37, 246, 28, 237, 165, 20, 216, 75, 57, 176,
+ 23, 182, 175, 91, 0, 236, 165, 225, 229, 130, 169, 196, 94, 72, 251,
+ 218, 96, 47, 77, 79, 36, 10, 127, 183, 247, 26, 181, 147, 63, 170,
+ 217, 192, 78, 236, 229, 120, 201, 117, 202, 187, 191, 181, 117, 146, 219,
+ 87, 243, 16, 214, 134, 239, 7, 123, 217, 119, 220, 210, 144, 216, 75,
+ 241, 151, 181, 20, 186, 5, 216, 203, 39, 69, 42, 9, 235, 183, 242,
+ 197, 245, 147, 107, 248, 5, 5, 18, 123, 217, 212, 113, 161, 34, 55,
+ 15, 216, 75, 249, 114, 213, 133, 239, 92, 53, 110, 136, 188, 164, 29,
+ 57, 251, 50, 92, 158, 88, 82, 221, 171, 47, 3, 246, 98, 186, 122,
+ 95, 216, 119, 30, 216, 75, 219, 147, 213, 82, 137, 189, 212, 111, 80,
+ 95, 161, 247, 69, 89, 229, 118, 47, 58, 165, 138, 250, 62, 1, 123,
+ 169, 176, 131, 220, 87, 61, 81, 142, 90, 165, 182, 71, 123, 217, 250,
+ 93, 143, 84, 49, 62, 166, 201, 175, 242, 69, 164, 18, 123, 33, 52,
+ 218, 11, 123, 46, 182, 23, 140, 109, 188, 189, 96, 172, 34, 246, 66,
+ 104, 140, 71, 236, 57, 218, 203, 72, 176, 151, 81, 96, 47, 236, 123,
+ 120, 143, 193, 94, 58, 85, 142, 166, 245, 106, 164, 189, 39, 216, 139,
+ 185, 132, 78, 205, 25, 248, 151, 165, 118, 210, 230, 91, 185, 214, 153,
+ 24, 51, 241, 47, 155, 117, 214, 31, 111, 192, 94, 246, 47, 32, 109,
+ 122, 201, 125, 126, 214, 250, 130, 189, 84, 254, 77, 167, 47, 248, 151,
+ 243, 247, 72, 155, 129, 242, 39, 103, 73, 223, 112, 121, 198, 110, 113,
+ 95, 19, 216, 203, 207, 179, 73, 155, 225, 242, 63, 23, 181, 26, 59,
+ 176, 151, 247, 106, 69, 139, 199, 11, 246, 242, 180, 123, 36, 173, 207,
+ 155, 180, 69, 187, 187, 19, 252, 203, 202, 190, 99, 205, 122, 254, 37,
+ 173, 15, 105, 51, 81, 14, 121, 61, 198, 76, 236, 229, 210, 156, 49,
+ 102, 61, 255, 242, 89, 250, 104, 90, 219, 71, 104, 180, 23, 246, 92,
+ 39, 159, 8, 246, 66, 247, 173, 204, 225, 222, 1, 254, 194, 57, 171,
+ 83, 109, 159, 163, 82, 184, 119, 104, 69, 253, 57, 43, 182, 99, 223,
+ 197, 97, 115, 175, 140, 10, 238, 206, 89, 93, 175, 93, 48, 230, 178,
+ 239, 226, 132, 115, 223, 197, 129, 185, 183, 38, 199, 90, 193, 221, 57,
+ 171, 107, 25, 232, 167, 217, 119, 113, 184, 113, 0, 77, 198, 226, 91,
+ 193, 221, 57, 171, 107, 25, 136, 109, 58, 142, 138, 206, 115, 86, 148,
+ 169, 204, 93, 253, 221, 157, 179, 186, 150, 129, 246, 64, 243, 137, 21,
+ 194, 157, 106, 221, 216, 220, 197, 106, 38, 244, 101, 217, 102, 17, 205,
+ 105, 156, 242, 137, 89, 248, 177, 216, 102, 53, 19, 26, 249, 137, 98,
+ 158, 83, 62, 49, 11, 63, 230, 251, 172, 102, 66, 35, 63, 145, 79,
+ 116, 202, 39, 250, 59, 243, 99, 216, 176, 154, 9, 141, 252, 68, 152,
+ 113, 218, 183, 50, 51, 204, 164, 7, 130, 29, 112, 235, 9, 215, 152,
+ 97, 181, 125, 254, 208, 55, 177, 161, 62, 102, 176, 29, 93, 131, 5,
+ 51, 254, 1, 254, 198, 97, 6, 249, 210, 53, 24, 208, 40, 83, 145,
+ 209, 208, 56, 204, 248, 115, 50, 112, 220, 100, 44, 105, 65, 198, 97,
+ 6, 249, 58, 237, 91, 105, 50, 66, 130, 140, 195, 76, 0, 103, 67,
+ 38, 175, 200, 84, 87, 152, 49, 141, 42, 231, 54, 102, 80, 199, 60,
+ 63, 87, 152, 65, 126, 238, 98, 6, 245, 73, 249, 121, 70, 166, 186,
+ 194, 12, 242, 115, 23, 51, 33, 65, 206, 239, 231, 10, 51, 200, 207,
+ 93, 204, 32, 78, 232, 253, 36, 159, 129, 29, 152, 245, 48, 195, 106,
+ 251, 66, 160, 111, 122, 125, 125, 204, 96, 59, 250, 45, 169, 6, 140,
+ 127, 104, 125, 227, 48, 131, 124, 233, 183, 164, 128, 70, 153, 74, 44,
+ 171, 103, 28, 102, 66, 56, 25, 56, 110, 50, 22, 107, 61, 227, 48,
+ 131, 124, 121, 204, 132, 104, 50, 124, 235, 25, 135, 25, 212, 123, 78,
+ 49, 195, 231, 184, 81, 199, 57, 197, 12, 207, 207, 90, 47, 231, 152,
+ 225, 249, 249, 214, 203, 57, 102, 248, 185, 25, 226, 132, 96, 38, 164,
+ 46, 216, 65, 160, 30, 102, 88, 109, 159, 47, 244, 77, 248, 68, 31,
+ 51, 216, 142, 126, 75, 234, 83, 198, 223, 255, 147, 156, 97, 134, 207,
+ 39, 34, 95, 250, 45, 41, 160, 81, 166, 146, 187, 254, 95, 206, 48,
+ 195, 231, 19, 125, 57, 25, 56, 110, 50, 22, 203, 255, 114, 134, 25,
+ 62, 159, 136, 124, 121, 204, 248, 106, 50, 210, 235, 230, 12, 51, 36,
+ 159, 24, 164, 233, 157, 216, 80, 232, 246, 130, 91, 43, 109, 29, 253,
+ 78, 62, 209, 226, 88, 102, 254, 59, 178, 100, 182, 249, 68, 167, 28,
+ 247, 255, 156, 249, 237, 154, 243, 213, 59, 249, 38, 228, 247, 121, 181,
+ 5, 217, 230, 155, 156, 206, 0, 113, 252, 28, 53, 11, 109, 173, 177,
+ 173, 96, 106, 214, 124, 68, 250, 237, 101, 230, 184, 203, 137, 217, 230,
+ 35, 156, 238, 158, 175, 203, 189, 223, 182, 130, 91, 227, 11, 190, 187,
+ 94, 245, 135, 247, 91, 84, 38, 38, 219, 245, 42, 31, 103, 16, 39,
+ 116, 110, 22, 0, 118, 240, 153, 30, 102, 88, 109, 95, 122, 29, 240,
+ 231, 181, 245, 49, 131, 237, 104, 12, 168, 195, 248, 87, 79, 111, 227,
+ 38, 102, 138, 186, 180, 3, 252, 255, 52, 6, 112, 50, 210, 225, 157,
+ 210, 53, 57, 213, 3, 58, 187, 137, 25, 215, 50, 240, 255, 211, 113,
+ 212, 230, 198, 1, 52, 25, 75, 223, 142, 239, 229, 114, 15, 51, 174,
+ 101, 224, 255, 167, 227, 168, 237, 140, 25, 148, 169, 140, 35, 173, 165,
+ 155, 152, 113, 45, 99, 231, 191, 234, 190, 213, 112, 47, 85, 239, 85,
+ 148, 150, 234, 153, 104, 212, 35, 225, 71, 104, 60, 19, 205, 158, 187,
+ 190, 215, 99, 107, 235, 76, 203, 247, 85, 167, 164, 144, 51, 209, 43,
+ 158, 169, 185, 243, 224, 33, 97, 210, 136, 15, 74, 101, 169, 33, 170,
+ 98, 138, 226, 242, 247, 119, 167, 44, 144, 24, 86, 151, 211, 124, 191,
+ 87, 244, 74, 73, 132, 85, 147, 82, 235, 182, 90, 242, 88, 190, 86,
+ 147, 155, 36, 141, 251, 106, 122, 138, 154, 159, 92, 39, 201, 47, 91,
+ 166, 136, 115, 70, 27, 165, 207, 150, 142, 79, 33, 231, 169, 71, 108,
+ 249, 86, 203, 223, 39, 75, 97, 31, 84, 23, 231, 254, 99, 237, 210,
+ 249, 106, 223, 213, 83, 159, 166, 73, 3, 150, 188, 215, 64, 149, 187,
+ 93, 58, 52, 48, 190, 129, 56, 247, 176, 75, 90, 31, 126, 96, 11,
+ 57, 139, 125, 98, 183, 99, 139, 42, 119, 159, 244, 212, 255, 201, 22,
+ 113, 223, 131, 210, 185, 233, 73, 245, 201, 89, 236, 251, 55, 91, 52,
+ 80, 251, 30, 149, 54, 239, 74, 212, 145, 123, 66, 42, 220, 35, 87,
+ 32, 57, 139, 189, 227, 246, 43, 173, 239, 25, 169, 103, 225, 7, 58,
+ 125, 207, 75, 219, 242, 183, 104, 64, 206, 98, 87, 11, 91, 83, 95,
+ 237, 123, 89, 58, 240, 225, 221, 205, 98, 61, 95, 147, 22, 87, 251,
+ 117, 11, 57, 139, 221, 170, 176, 90, 247, 233, 25, 125, 91, 26, 208,
+ 108, 113, 178, 88, 238, 93, 233, 248, 223, 249, 83, 200, 89, 236, 139,
+ 129, 149, 181, 223, 247, 161, 116, 51, 41, 72, 103, 143, 229, 137, 212,
+ 97, 76, 227, 20, 114, 22, 187, 219, 244, 38, 218, 239, 251, 82, 234,
+ 189, 164, 169, 78, 223, 215, 82, 249, 163, 117, 73, 27, 249, 238, 214,
+ 122, 170, 92, 179, 135, 108, 91, 221, 80, 108, 87, 105, 158, 242, 94,
+ 223, 182, 90, 27, 47, 249, 229, 228, 112, 173, 111, 110, 249, 7, 211,
+ 4, 157, 190, 121, 228, 34, 219, 22, 106, 109, 242, 202, 253, 191, 93,
+ 175, 245, 205, 39, 239, 188, 191, 87, 167, 175, 143, 44, 21, 184, 171,
+ 181, 121, 79, 126, 147, 223, 83, 205, 213, 155, 11, 200, 29, 103, 23,
+ 176, 137, 251, 22, 148, 43, 39, 19, 156, 250, 202, 45, 211, 253, 181,
+ 190, 133, 229, 17, 215, 171, 234, 244, 45, 34, 179, 61, 58, 63, 74,
+ 159, 27, 243, 190, 204, 239, 221, 249, 120, 84, 49, 21, 132, 191, 34,
+ 30, 85, 156, 230, 127, 138, 31, 2, 223, 76, 252, 16, 214, 50, 162,
+ 175, 37, 126, 136, 208, 193, 224, 135, 216, 115, 215, 126, 104, 19, 248,
+ 161, 73, 211, 6, 211, 154, 169, 164, 120, 117, 62, 219, 16, 252, 80,
+ 193, 70, 191, 113, 126, 168, 178, 82, 203, 24, 197, 237, 11, 161, 31,
+ 98, 49, 126, 57, 221, 71, 66, 63, 36, 138, 241, 196, 15, 37, 29,
+ 75, 177, 17, 63, 228, 255, 249, 46, 27, 241, 67, 227, 109, 135, 108,
+ 122, 126, 232, 147, 149, 187, 109, 196, 15, 21, 59, 170, 237, 41, 129,
+ 31, 122, 241, 226, 136, 206, 62, 137, 93, 250, 170, 231, 85, 27, 241,
+ 67, 23, 199, 223, 176, 17, 63, 52, 224, 247, 219, 54, 61, 63, 36,
+ 247, 38, 123, 86, 123, 164, 31, 219, 95, 212, 250, 238, 147, 30, 124,
+ 113, 222, 166, 231, 135, 230, 103, 92, 176, 17, 63, 52, 235, 249, 57,
+ 27, 241, 67, 19, 77, 103, 109, 122, 126, 232, 230, 193, 99, 54, 226,
+ 135, 110, 141, 59, 102, 35, 126, 232, 118, 141, 99, 54, 61, 63, 244,
+ 100, 196, 105, 27, 241, 67, 77, 125, 206, 106, 239, 124, 89, 154, 183,
+ 248, 156, 78, 223, 107, 210, 23, 59, 201, 187, 221, 148, 218, 154, 200,
+ 59, 223, 150, 186, 4, 233, 245, 189, 43, 213, 142, 39, 58, 201, 144,
+ 98, 147, 72, 223, 135, 210, 145, 243, 122, 227, 125, 34, 237, 137, 63,
+ 101, 35, 126, 168, 200, 193, 147, 54, 226, 135, 58, 23, 59, 97, 211,
+ 243, 67, 11, 70, 81, 157, 200, 37, 226, 143, 218, 136, 31, 250, 126,
+ 166, 216, 54, 176, 38, 100, 93, 200, 113, 27, 241, 67, 129, 245, 14,
+ 218, 136, 31, 218, 90, 254, 111, 155, 158, 31, 202, 252, 125, 157, 141,
+ 248, 161, 194, 214, 165, 54, 226, 135, 170, 118, 248, 65, 252, 206, 224,
+ 135, 154, 140, 140, 177, 17, 63, 180, 171, 239, 112, 234, 135, 90, 117,
+ 234, 167, 235, 135, 98, 170, 140, 165, 126, 104, 173, 35, 150, 250, 161,
+ 95, 215, 76, 212, 245, 67, 108, 239, 215, 143, 210, 232, 135, 248, 61,
+ 97, 31, 143, 202, 224, 135, 42, 131, 31, 170, 252, 142, 31, 194, 249,
+ 27, 241, 67, 117, 192, 15, 225, 124, 140, 248, 33, 66, 251, 130, 31,
+ 98, 207, 93, 215, 84, 159, 106, 153, 105, 217, 59, 238, 137, 157, 248,
+ 33, 219, 179, 252, 202, 92, 255, 252, 224, 48, 105, 250, 238, 114, 169,
+ 204, 15, 149, 1, 63, 84, 10, 252, 80, 73, 218, 247, 231, 137, 11,
+ 36, 182, 54, 88, 78, 247, 39, 87, 131, 31, 18, 173, 13, 176, 239,
+ 124, 240, 67, 81, 117, 138, 216, 137, 31, 122, 254, 170, 182, 66, 23,
+ 138, 91, 39, 189, 120, 212, 70, 184, 119, 55, 125, 242, 70, 105, 81,
+ 129, 221, 180, 30, 59, 104, 137, 250, 158, 159, 140, 79, 150, 170, 222,
+ 234, 40, 92, 199, 175, 29, 101, 151, 118, 46, 93, 147, 74, 252, 80,
+ 224, 201, 93, 10, 93, 115, 244, 118, 201, 49, 236, 156, 176, 111, 25,
+ 240, 67, 167, 111, 253, 147, 74, 252, 80, 100, 137, 11, 10, 221, 10,
+ 252, 208, 31, 77, 174, 10, 251, 182, 138, 59, 40, 221, 124, 118, 55,
+ 149, 248, 161, 164, 230, 207, 20, 186, 60, 248, 161, 41, 33, 166, 173,
+ 194, 189, 89, 240, 67, 59, 46, 228, 219, 74, 252, 208, 226, 203, 42,
+ 125, 23, 252, 208, 152, 235, 249, 132, 125, 143, 96, 109, 90, 11, 194,
+ 223, 33, 249, 44, 83, 229, 174, 143, 186, 44, 125, 244, 215, 61, 225,
+ 59, 223, 1, 63, 148, 239, 244, 245, 84, 226, 135, 174, 238, 184, 168,
+ 208, 143, 162, 110, 75, 101, 254, 60, 37, 236, 187, 11, 252, 208, 164,
+ 190, 135, 83, 137, 31, 170, 26, 176, 79, 161, 79, 68, 61, 148, 22,
+ 60, 223, 41, 236, 123, 23, 252, 208, 119, 189, 183, 165, 18, 63, 244,
+ 96, 108, 170, 66, 123, 131, 31, 234, 146, 144, 34, 236, 219, 44, 238,
+ 181, 84, 107, 86, 50, 105, 35, 119, 201, 220, 160, 254, 70, 224, 135,
+ 230, 244, 249, 83, 216, 183, 15, 248, 161, 237, 127, 47, 77, 37, 126,
+ 40, 224, 192, 124, 133, 238, 15, 126, 104, 251, 222, 233, 194, 190, 23,
+ 192, 15, 61, 249, 136, 228, 144, 242, 202, 251, 39, 169, 251, 195, 169,
+ 193, 249, 228, 207, 110, 215, 19, 246, 93, 8, 126, 104, 66, 177, 146,
+ 169, 196, 15, 149, 159, 158, 71, 161, 255, 10, 46, 32, 47, 42, 126,
+ 83, 136, 133, 116, 240, 67, 229, 158, 239, 179, 19, 63, 180, 183, 101,
+ 170, 66, 63, 8, 46, 44, 63, 249, 109, 173, 176, 239, 107, 240, 67,
+ 236, 76, 129, 31, 165, 207, 131, 31, 226, 207, 26, 248, 120, 148, 3,
+ 63, 84, 14, 252, 80, 185, 119, 231, 67, 176, 198, 227, 231, 67, 184,
+ 102, 35, 126, 136, 208, 184, 46, 99, 207, 93, 223, 235, 102, 135, 249,
+ 208, 79, 199, 163, 104, 173, 234, 244, 25, 42, 45, 193, 124, 40, 195,
+ 28, 197, 213, 170, 142, 4, 63, 52, 18, 252, 208, 72, 182, 31, 15,
+ 243, 33, 150, 83, 88, 78, 247, 189, 61, 193, 15, 137, 114, 10, 106,
+ 220, 90, 45, 253, 189, 135, 180, 73, 146, 198, 172, 81, 233, 50, 48,
+ 31, 170, 57, 87, 188, 159, 108, 141, 219, 40, 125, 95, 192, 74, 235,
+ 92, 79, 29, 83, 247, 135, 207, 195, 124, 200, 54, 85, 188, 175, 107,
+ 129, 249, 80, 205, 149, 164, 222, 49, 77, 138, 243, 80, 235, 32, 199,
+ 68, 109, 151, 54, 119, 236, 43, 236, 155, 1, 126, 232, 100, 173, 190,
+ 180, 70, 182, 244, 76, 181, 70, 246, 125, 240, 67, 157, 239, 246, 18,
+ 246, 173, 0, 126, 168, 235, 10, 86, 35, 59, 176, 128, 90, 35, 91,
+ 28, 252, 144, 121, 72, 23, 97, 223, 21, 224, 135, 252, 127, 106, 79,
+ 107, 100, 135, 207, 83, 233, 175, 193, 15, 237, 153, 219, 94, 216, 247,
+ 58, 248, 33, 207, 65, 93, 104, 141, 236, 154, 199, 106, 61, 238, 69,
+ 240, 67, 101, 35, 123, 8, 251, 62, 2, 63, 212, 46, 162, 23, 173,
+ 145, 141, 170, 22, 166, 213, 125, 222, 150, 126, 188, 208, 71, 216, 247,
+ 1, 248, 161, 31, 31, 176, 251, 228, 194, 139, 171, 181, 167, 248, 77,
+ 137, 250, 13, 7, 10, 251, 98, 141, 236, 145, 251, 3, 105, 141, 108,
+ 224, 164, 65, 102, 50, 31, 90, 90, 46, 92, 216, 55, 47, 248, 161,
+ 136, 206, 180, 141, 60, 161, 251, 96, 90, 35, 187, 52, 44, 66, 216,
+ 55, 55, 248, 161, 13, 195, 135, 210, 26, 217, 4, 179, 90, 231, 234,
+ 5, 126, 104, 140, 207, 72, 97, 223, 103, 224, 135, 138, 158, 34, 185,
+ 103, 88, 151, 117, 85, 207, 29, 188, 0, 63, 180, 230, 234, 56, 241,
+ 120, 193, 15, 205, 44, 18, 69, 235, 107, 187, 167, 170, 244, 91, 240,
+ 67, 1, 253, 197, 231, 35, 112, 62, 244, 123, 18, 105, 227, 43, 231,
+ 58, 173, 210, 56, 31, 10, 245, 136, 49, 235, 205, 135, 216, 89, 21,
+ 63, 74, 227, 124, 136, 63, 195, 226, 227, 49, 10, 252, 208, 40, 240,
+ 67, 163, 222, 201, 163, 99, 30, 144, 158, 203, 45, 19, 238, 29, 82,
+ 87, 47, 39, 200, 106, 115, 67, 160, 111, 98, 57, 55, 246, 158, 2,
+ 184, 125, 206, 242, 220, 126, 109, 57, 3, 247, 107, 203, 115, 251, 181,
+ 64, 163, 76, 197, 67, 148, 53, 112, 191, 150, 147, 129, 227, 38, 99,
+ 9, 41, 107, 224, 126, 109, 185, 44, 251, 181, 154, 12, 71, 25, 3,
+ 247, 107, 203, 25, 187, 95, 139, 58, 54, 114, 191, 54, 164, 172, 177,
+ 251, 181, 168, 59, 35, 247, 107, 17, 39, 180, 206, 176, 68, 184, 119,
+ 122, 128, 30, 102, 88, 109, 174, 163, 116, 184, 119, 104, 41, 55, 206,
+ 5, 149, 230, 206, 211, 148, 230, 206, 5, 149, 52, 240, 92, 16, 39,
+ 195, 1, 239, 228, 208, 228, 88, 75, 26, 120, 46, 168, 20, 55, 14,
+ 160, 201, 88, 124, 75, 26, 120, 46, 168, 84, 150, 115, 65, 165, 180,
+ 115, 65, 37, 12, 60, 23, 84, 210, 216, 253, 90, 107, 73, 99, 247,
+ 107, 125, 75, 26, 187, 95, 139, 186, 51, 114, 191, 22, 113, 66, 235,
+ 12, 139, 130, 29, 148, 209, 195, 12, 119, 247, 99, 241, 112, 111, 255,
+ 98, 110, 212, 127, 20, 231, 98, 64, 113, 198, 63, 233, 253, 156, 97,
+ 166, 88, 209, 143, 26, 210, 24, 192, 201, 72, 132, 119, 74, 212, 228,
+ 88, 222, 207, 25, 102, 254, 57, 81, 139, 125, 239, 181, 24, 55, 14,
+ 160, 201, 88, 210, 253, 114, 134, 153, 162, 195, 186, 178, 113, 20, 203,
+ 82, 255, 81, 76, 229, 29, 234, 151, 51, 204, 28, 168, 206, 213, 25,
+ 190, 207, 217, 80, 22, 126, 168, 83, 198, 219, 245, 191, 119, 246, 87,
+ 5, 252, 80, 127, 255, 149, 31, 234, 51, 59, 126, 168, 171, 255, 202,
+ 47, 84, 192, 15, 245, 226, 46, 63, 90, 103, 88, 148, 97, 38, 32,
+ 6, 236, 160, 132, 14, 102, 248, 187, 31, 161, 175, 163, 176, 62, 102,
+ 176, 29, 141, 1, 69, 24, 255, 136, 194, 198, 197, 25, 228, 75, 99,
+ 0, 208, 40, 83, 105, 84, 216, 184, 56, 19, 202, 201, 192, 113, 147,
+ 177, 36, 248, 26, 23, 103, 144, 175, 83, 157, 161, 38, 35, 41, 198,
+ 184, 56, 131, 122, 55, 50, 206, 152, 10, 27, 27, 103, 80, 159, 70,
+ 198, 25, 212, 157, 145, 113, 6, 113, 66, 48, 147, 49, 22, 236, 160,
+ 168, 30, 102, 216, 153, 237, 164, 232, 112, 239, 128, 40, 125, 204, 96,
+ 59, 98, 7, 1, 209, 140, 127, 90, 164, 113, 152, 9, 224, 100, 36,
+ 193, 59, 37, 105, 114, 66, 34, 141, 195, 12, 242, 165, 227, 0, 154,
+ 140, 197, 49, 206, 56, 204, 4, 68, 57, 99, 6, 101, 42, 254, 101,
+ 156, 113, 152, 65, 189, 27, 185, 158, 9, 137, 52, 118, 61, 131, 250,
+ 52, 114, 61, 19, 49, 206, 216, 245, 12, 226, 132, 222, 97, 52, 4,
+ 236, 32, 70, 128, 153, 161, 253, 76, 125, 135, 179, 223, 35, 2, 250,
+ 102, 140, 214, 199, 12, 182, 35, 118, 144, 49, 134, 241, 79, 28, 153,
+ 189, 29, 116, 191, 227, 101, 75, 159, 82, 52, 72, 84, 155, 235, 8,
+ 241, 160, 119, 63, 34, 95, 34, 35, 2, 104, 148, 169, 96, 102, 120,
+ 246, 50, 230, 60, 219, 106, 251, 241, 236, 252, 32, 81, 109, 238, 44,
+ 207, 82, 20, 51, 17, 156, 12, 28, 55, 29, 203, 208, 236, 101, 60,
+ 223, 113, 38, 53, 237, 227, 163, 65, 162, 218, 220, 198, 246, 191, 232,
+ 252, 15, 249, 242, 152, 137, 208, 100, 164, 15, 202, 94, 198, 213, 94,
+ 125, 204, 193, 30, 177, 194, 218, 220, 95, 158, 176, 218, 92, 212, 59,
+ 95, 11, 133, 122, 36, 252, 8, 141, 181, 80, 236, 57, 230, 129, 171,
+ 154, 150, 193, 223, 10, 110, 63, 30, 107, 161, 230, 253, 91, 88, 107,
+ 211, 66, 38, 237, 177, 22, 106, 212, 235, 87, 194, 250, 55, 172, 181,
+ 188, 21, 113, 77, 107, 243, 173, 28, 121, 236, 159, 64, 181, 111, 39,
+ 185, 208, 167, 251, 116, 250, 134, 202, 247, 46, 164, 104, 109, 122, 201,
+ 77, 63, 248, 83, 161, 115, 101, 246, 149, 195, 234, 139, 239, 100, 125,
+ 157, 107, 176, 124, 166, 246, 100, 173, 205, 112, 185, 254, 180, 33, 129,
+ 106, 206, 109, 132, 92, 234, 68, 191, 64, 113, 206, 109, 164, 124, 36,
+ 79, 31, 173, 205, 104, 185, 119, 175, 111, 180, 190, 99, 228, 23, 219,
+ 154, 232, 244, 29, 43, 135, 238, 247, 211, 218, 68, 202, 203, 27, 21,
+ 81, 199, 27, 109, 149, 119, 87, 206, 43, 30, 111, 108, 188, 220, 40,
+ 101, 137, 214, 102, 162, 124, 239, 223, 149, 90, 223, 201, 242, 143, 101,
+ 254, 210, 233, 59, 77, 94, 108, 137, 215, 218, 204, 164, 52, 214, 66,
+ 177, 231, 217, 199, 105, 180, 23, 196, 16, 111, 47, 136, 9, 98, 47,
+ 132, 70, 123, 97, 207, 201, 57, 10, 231, 243, 92, 104, 47, 173, 31,
+ 150, 165, 181, 185, 164, 61, 218, 139, 103, 253, 146, 186, 181, 185, 47,
+ 90, 20, 163, 181, 185, 95, 127, 252, 62, 173, 205, 93, 91, 216, 207,
+ 166, 103, 47, 227, 182, 23, 181, 17, 123, 177, 135, 22, 181, 17, 123,
+ 25, 112, 161, 136, 77, 207, 94, 38, 31, 44, 76, 235, 107, 223, 236,
+ 40, 98, 35, 246, 178, 192, 163, 168, 77, 207, 94, 6, 28, 34, 239,
+ 54, 90, 110, 28, 95, 212, 70, 236, 165, 108, 189, 34, 54, 61, 123,
+ 233, 183, 175, 0, 173, 205, 141, 126, 146, 143, 214, 114, 255, 214, 232,
+ 73, 138, 158, 189, 100, 164, 39, 165, 16, 123, 241, 54, 111, 73, 33,
+ 246, 82, 110, 245, 182, 20, 61, 123, 41, 86, 185, 36, 173, 205, 37,
+ 52, 218, 11, 123, 46, 182, 23, 244, 135, 188, 189, 160, 127, 35, 246,
+ 66, 232, 79, 192, 94, 216, 115, 180, 151, 178, 239, 236, 119, 239, 4,
+ 123, 233, 82, 117, 18, 189, 35, 146, 180, 127, 15, 236, 229, 180, 148,
+ 38, 220, 167, 51, 53, 106, 39, 159, 142, 188, 72, 107, 115, 175, 212,
+ 80, 247, 235, 189, 192, 94, 98, 7, 228, 22, 206, 79, 61, 26, 133,
+ 202, 231, 7, 21, 73, 37, 246, 178, 113, 134, 186, 87, 158, 15, 236,
+ 229, 139, 205, 181, 132, 125, 243, 120, 13, 150, 251, 133, 53, 74, 37,
+ 246, 210, 120, 76, 251, 84, 117, 31, 98, 132, 236, 27, 221, 89, 216,
+ 215, 107, 219, 72, 57, 176, 114, 207, 84, 98, 47, 15, 246, 246, 211,
+ 250, 142, 145, 15, 15, 22, 207, 169, 159, 130, 189, 164, 118, 141, 161,
+ 181, 185, 121, 151, 71, 42, 116, 27, 176, 151, 106, 7, 134, 136, 247,
+ 247, 193, 94, 198, 7, 123, 209, 218, 220, 15, 60, 212, 239, 149, 183,
+ 3, 123, 57, 180, 195, 67, 172, 171, 184, 105, 242, 254, 120, 86, 155,
+ 75, 232, 149, 96, 47, 236, 185, 216, 94, 48, 182, 57, 213, 254, 63,
+ 97, 103, 157, 9, 141, 254, 133, 61, 71, 123, 25, 245, 206, 190, 36,
+ 126, 43, 226, 139, 132, 24, 90, 155, 75, 218, 99, 237, 255, 134, 147,
+ 209, 102, 61, 255, 210, 127, 84, 52, 173, 205, 157, 93, 153, 244, 237,
+ 36, 111, 62, 18, 165, 91, 155, 107, 233, 21, 69, 107, 115, 77, 215,
+ 213, 61, 77, 47, 176, 151, 149, 13, 35, 197, 125, 193, 191, 236, 108,
+ 49, 142, 214, 215, 78, 148, 198, 154, 137, 127, 249, 235, 205, 24, 179,
+ 158, 127, 121, 188, 144, 180, 25, 45, 123, 53, 24, 99, 38, 254, 197,
+ 239, 31, 241, 154, 233, 13, 216, 75, 116, 230, 40, 90, 155, 219, 168,
+ 232, 104, 237, 91, 182, 86, 249, 235, 240, 209, 58, 123, 124, 241, 114,
+ 252, 158, 40, 90, 155, 27, 127, 37, 74, 235, 59, 89, 142, 127, 19,
+ 165, 91, 155, 91, 233, 24, 171, 205, 37, 52, 250, 23, 246, 92, 188,
+ 206, 195, 121, 42, 173, 153, 234, 15, 243, 176, 177, 194, 57, 171, 83,
+ 109, 174, 9, 250, 166, 15, 212, 159, 179, 98, 59, 250, 189, 215, 8,
+ 174, 102, 106, 160, 187, 115, 86, 215, 107, 23, 140, 185, 244, 123, 175,
+ 17, 220, 57, 115, 156, 223, 13, 209, 106, 166, 6, 184, 59, 103, 205,
+ 38, 103, 9, 126, 154, 238, 191, 13, 226, 206, 203, 195, 187, 147, 177,
+ 88, 7, 184, 59, 103, 117, 45, 3, 177, 77, 207, 203, 15, 204, 82,
+ 51, 165, 205, 85, 125, 7, 184, 59, 103, 117, 45, 3, 237, 129, 230,
+ 215, 6, 58, 215, 170, 178, 185, 139, 213, 76, 104, 172, 85, 21, 205,
+ 105, 248, 117, 20, 234, 152, 231, 199, 98, 155, 213, 76, 104, 228, 39,
+ 138, 121, 78, 181, 190, 89, 248, 49, 223, 103, 53, 19, 26, 249, 137,
+ 124, 162, 83, 173, 111, 22, 126, 12, 27, 86, 51, 161, 145, 159, 8,
+ 51, 252, 58, 15, 113, 66, 107, 166, 194, 192, 14, 134, 232, 97, 134,
+ 213, 230, 250, 66, 223, 132, 190, 110, 212, 76, 245, 231, 106, 141, 250,
+ 113, 53, 83, 125, 141, 195, 12, 242, 165, 53, 83, 64, 163, 76, 37,
+ 183, 208, 199, 56, 204, 248, 114, 50, 112, 220, 100, 44, 150, 62, 198,
+ 97, 6, 249, 58, 213, 76, 105, 50, 210, 195, 140, 195, 12, 234, 157,
+ 207, 21, 184, 194, 12, 230, 10, 220, 197, 12, 234, 152, 231, 231, 10,
+ 51, 200, 207, 93, 204, 88, 120, 126, 111, 198, 165, 186, 194, 140, 101,
+ 68, 57, 183, 49, 131, 186, 227, 223, 207, 21, 102, 240, 253, 220, 197,
+ 12, 226, 132, 96, 198, 183, 7, 216, 65, 127, 61, 204, 176, 218, 220,
+ 244, 222, 225, 222, 33, 189, 220, 168, 153, 234, 205, 197, 128, 222, 140,
+ 191, 163, 167, 113, 152, 9, 225, 100, 164, 195, 59, 165, 107, 114, 34,
+ 122, 26, 135, 25, 228, 75, 199, 1, 52, 29, 75, 79, 227, 48, 19,
+ 210, 43, 75, 205, 84, 47, 45, 207, 223, 195, 56, 204, 160, 222, 115,
+ 138, 25, 62, 199, 29, 209, 51, 231, 152, 113, 202, 233, 247, 204, 57,
+ 102, 156, 114, 250, 61, 114, 142, 25, 126, 110, 134, 56, 161, 103, 138,
+ 186, 128, 29, 132, 233, 97, 134, 213, 230, 38, 116, 15, 247, 78, 236,
+ 166, 143, 25, 108, 71, 99, 64, 119, 238, 76, 81, 183, 156, 97, 134,
+ 207, 39, 250, 114, 50, 18, 66, 1, 251, 154, 156, 180, 174, 57, 195,
+ 12, 159, 79, 68, 190, 116, 63, 25, 222, 157, 140, 37, 164, 107, 206,
+ 48, 195, 231, 19, 145, 47, 143, 25, 148, 169, 140, 181, 75, 206, 48,
+ 67, 242, 137, 65, 154, 222, 169, 13, 109, 43, 184, 53, 108, 97, 222,
+ 119, 242, 137, 88, 171, 154, 250, 215, 219, 192, 236, 242, 137, 78, 103,
+ 138, 186, 114, 181, 180, 105, 5, 183, 254, 89, 98, 89, 74, 214, 124,
+ 147, 47, 240, 251, 95, 169, 234, 217, 230, 155, 156, 114, 250, 28, 63,
+ 203, 129, 130, 91, 131, 194, 174, 188, 147, 143, 176, 92, 90, 102, 254,
+ 227, 208, 234, 108, 243, 17, 78, 57, 253, 46, 206, 227, 237, 60, 238,
+ 221, 245, 42, 142, 183, 88, 193, 152, 108, 215, 171, 78, 103, 138, 186,
+ 112, 231, 35, 58, 2, 221, 67, 15, 51, 220, 189, 155, 157, 195, 189,
+ 67, 59, 185, 113, 166, 168, 51, 183, 15, 219, 153, 139, 51, 167, 91,
+ 184, 137, 25, 215, 245, 166, 121, 255, 215, 184, 62, 221, 135, 229, 100,
+ 56, 224, 157, 28, 154, 156, 18, 99, 90, 187, 137, 25, 215, 50, 42,
+ 124, 153, 196, 190, 247, 218, 137, 27, 7, 208, 100, 44, 37, 190, 8,
+ 113, 19, 51, 174, 101, 148, 77, 219, 199, 246, 147, 59, 101, 57, 83,
+ 212, 73, 149, 145, 55, 95, 27, 55, 49, 227, 90, 198, 5, 174, 54,
+ 23, 245, 206, 215, 230, 162, 30, 9, 63, 66, 227, 25, 112, 246, 60,
+ 251, 218, 220, 232, 113, 73, 26, 174, 2, 164, 66, 219, 47, 42, 180,
+ 60, 36, 76, 154, 190, 46, 31, 205, 223, 183, 133, 62, 125, 224, 47,
+ 138, 235, 251, 124, 202, 2, 137, 97, 117, 57, 205, 247, 227, 25, 112,
+ 17, 86, 77, 218, 25, 240, 25, 242, 125, 173, 77, 146, 180, 97, 210,
+ 99, 45, 39, 189, 78, 58, 123, 224, 133, 56, 23, 30, 187, 81, 154,
+ 188, 179, 136, 38, 119, 179, 84, 241, 185, 143, 66, 231, 138, 78, 150,
+ 54, 215, 204, 21, 36, 206, 31, 216, 165, 192, 190, 27, 52, 254, 105,
+ 82, 193, 51, 9, 106, 14, 62, 122, 187, 116, 124, 94, 71, 161, 92,
+ 83, 220, 46, 105, 247, 247, 205, 181, 54, 123, 164, 223, 154, 28, 111,
+ 160, 202, 221, 39, 5, 63, 243, 169, 47, 234, 155, 25, 123, 80, 242,
+ 120, 48, 80, 243, 67, 233, 210, 183, 179, 22, 168, 116, 244, 81, 233,
+ 245, 111, 105, 58, 57, 213, 19, 210, 208, 32, 226, 195, 78, 73, 255,
+ 244, 94, 171, 229, 99, 207, 72, 65, 179, 82, 116, 234, 152, 207, 75,
+ 77, 182, 29, 214, 218, 56, 164, 143, 22, 188, 76, 81, 223, 249, 178,
+ 180, 48, 89, 156, 67, 206, 140, 189, 38, 149, 105, 218, 138, 214, 196,
+ 217, 71, 132, 168, 121, 111, 172, 137, 251, 237, 43, 221, 154, 184, 159,
+ 254, 87, 150, 214, 196, 101, 78, 240, 209, 106, 241, 30, 74, 199, 215,
+ 220, 215, 173, 205, 45, 219, 242, 28, 173, 205, 237, 125, 249, 184, 86,
+ 215, 251, 82, 90, 51, 234, 160, 110, 109, 110, 197, 149, 23, 104, 109,
+ 110, 194, 202, 19, 180, 54, 247, 245, 202, 3, 186, 181, 185, 131, 226,
+ 214, 210, 218, 220, 123, 45, 102, 209, 218, 220, 180, 90, 29, 117, 107,
+ 115, 223, 92, 74, 214, 234, 79, 243, 202, 235, 122, 236, 221, 164, 246,
+ 205, 39, 95, 253, 97, 67, 3, 113, 95, 31, 249, 250, 202, 214, 154,
+ 93, 189, 39, 151, 95, 55, 67, 219, 23, 42, 32, 167, 205, 92, 175,
+ 179, 47, 84, 80, 94, 52, 230, 140, 214, 198, 87, 110, 242, 213, 29,
+ 173, 111, 97, 249, 214, 7, 111, 116, 250, 22, 145, 217, 30, 157, 31,
+ 165, 241, 12, 56, 191, 119, 231, 227, 81, 213, 84, 16, 254, 138, 120,
+ 84, 125, 167, 22, 5, 125, 51, 241, 67, 211, 193, 15, 161, 175, 37,
+ 126, 136, 208, 102, 240, 67, 236, 185, 107, 63, 180, 17, 252, 208, 159,
+ 109, 231, 211, 123, 70, 199, 141, 155, 169, 208, 173, 193, 15, 237, 73,
+ 142, 231, 252, 80, 53, 240, 67, 213, 192, 15, 177, 251, 12, 95, 128,
+ 31, 98, 49, 126, 57, 221, 71, 242, 0, 63, 36, 138, 241, 196, 15,
+ 45, 178, 215, 167, 181, 185, 7, 110, 5, 218, 136, 31, 122, 249, 126,
+ 176, 110, 109, 238, 165, 243, 53, 104, 109, 238, 245, 253, 31, 219, 136,
+ 31, 186, 191, 69, 252, 205, 219, 92, 113, 118, 105, 87, 70, 51, 90,
+ 155, 59, 249, 155, 161, 218, 55, 56, 183, 75, 17, 93, 103, 10, 251,
+ 62, 141, 221, 37, 245, 248, 114, 55, 173, 205, 61, 220, 228, 8, 173,
+ 205, 45, 41, 157, 213, 173, 205, 253, 170, 251, 86, 90, 155, 235, 215,
+ 101, 3, 173, 205, 61, 245, 237, 10, 155, 56, 87, 127, 66, 74, 120,
+ 243, 43, 173, 205, 125, 82, 102, 182, 246, 206, 103, 164, 38, 35, 35,
+ 197, 251, 96, 224, 135, 138, 174, 169, 78, 107, 115, 119, 238, 124, 168,
+ 252, 94, 111, 163, 46, 75, 121, 107, 205, 77, 209, 243, 67, 3, 138,
+ 94, 79, 38, 126, 232, 169, 41, 81, 253, 166, 0, 248, 33, 191, 34,
+ 71, 27, 136, 229, 222, 149, 174, 109, 148, 2, 137, 31, 42, 83, 187,
+ 67, 32, 241, 67, 95, 252, 17, 17, 168, 231, 135, 174, 79, 168, 31,
+ 72, 252, 208, 166, 247, 106, 4, 18, 63, 52, 245, 187, 18, 129, 122,
+ 126, 232, 204, 69, 178, 95, 107, 146, 219, 12, 240, 12, 36, 126, 104,
+ 246, 221, 139, 13, 244, 252, 80, 226, 134, 245, 13, 136, 31, 234, 177,
+ 245, 117, 125, 226, 135, 102, 183, 59, 182, 69, 207, 15, 21, 251, 188,
+ 34, 253, 70, 192, 197, 9, 221, 233, 55, 2, 118, 119, 79, 208, 253,
+ 70, 192, 179, 15, 22, 211, 111, 4, 60, 63, 189, 49, 133, 248, 161,
+ 204, 201, 7, 83, 244, 252, 208, 190, 67, 79, 83, 136, 31, 170, 177,
+ 40, 55, 173, 205, 253, 247, 104, 33, 221, 218, 92, 182, 247, 235, 71,
+ 105, 244, 67, 252, 158, 176, 232, 27, 1, 56, 127, 35, 126, 168, 50,
+ 248, 33, 156, 143, 17, 63, 68, 232, 194, 224, 135, 216, 115, 215, 181,
+ 185, 105, 45, 51, 45, 63, 127, 243, 146, 214, 230, 174, 120, 163, 214,
+ 230, 22, 3, 63, 180, 237, 227, 50, 194, 218, 220, 197, 224, 135, 216,
+ 218, 96, 57, 221, 159, 244, 3, 63, 36, 90, 27, 96, 223, 123, 224,
+ 135, 110, 252, 246, 3, 173, 205, 141, 45, 49, 67, 221, 111, 4, 63,
+ 212, 102, 90, 188, 112, 175, 178, 101, 220, 70, 233, 211, 162, 83, 104,
+ 109, 238, 130, 179, 125, 20, 218, 10, 126, 232, 195, 248, 134, 194, 190,
+ 131, 97, 62, 228, 63, 99, 20, 245, 67, 151, 231, 239, 84, 126, 195,
+ 212, 168, 237, 82, 88, 254, 230, 58, 54, 190, 75, 106, 80, 167, 2,
+ 253, 86, 201, 240, 193, 241, 74, 223, 254, 224, 135, 94, 62, 54, 9,
+ 127, 243, 21, 241, 7, 165, 144, 133, 85, 169, 31, 58, 253, 67, 1,
+ 229, 61, 95, 91, 143, 74, 63, 72, 67, 133, 239, 252, 19, 248, 161,
+ 157, 253, 30, 208, 123, 150, 111, 204, 174, 164, 252, 46, 255, 195, 154,
+ 184, 200, 86, 194, 188, 197, 142, 184, 243, 210, 245, 95, 172, 236, 254,
+ 243, 195, 243, 20, 250, 36, 248, 161, 231, 30, 226, 90, 85, 71, 228,
+ 53, 201, 199, 124, 146, 214, 230, 22, 41, 171, 214, 34, 207, 143, 186,
+ 45, 237, 185, 117, 77, 216, 55, 22, 252, 80, 163, 58, 71, 104, 109,
+ 174, 215, 133, 125, 90, 77, 240, 67, 105, 255, 52, 113, 109, 238, 85,
+ 240, 67, 35, 62, 98, 181, 185, 105, 77, 213, 218, 220, 220, 224, 135,
+ 170, 134, 234, 215, 230, 166, 218, 89, 109, 238, 207, 245, 55, 42, 116,
+ 8, 248, 161, 216, 245, 226, 241, 246, 223, 230, 41, 215, 121, 194, 106,
+ 115, 59, 159, 82, 107, 115, 7, 130, 31, 10, 93, 47, 174, 205, 61,
+ 9, 126, 168, 116, 195, 193, 180, 54, 247, 247, 196, 182, 234, 55, 151,
+ 131, 243, 201, 62, 5, 197, 181, 185, 75, 192, 15, 109, 241, 103, 181,
+ 185, 247, 207, 169, 181, 185, 91, 130, 11, 200, 195, 155, 220, 18, 218,
+ 198, 17, 240, 67, 131, 106, 30, 160, 181, 185, 193, 83, 183, 210, 218,
+ 220, 248, 127, 215, 233, 214, 230, 178, 51, 5, 126, 148, 198, 218, 92,
+ 254, 172, 129, 168, 54, 23, 215, 120, 124, 109, 238, 5, 174, 54, 247,
+ 2, 87, 155, 123, 193, 141, 218, 220, 113, 251, 88, 109, 110, 105, 173,
+ 54, 23, 215, 101, 133, 191, 20, 215, 230, 226, 186, 140, 229, 20, 150,
+ 211, 125, 111, 92, 151, 137, 114, 10, 100, 62, 148, 191, 41, 171, 205,
+ 173, 212, 149, 124, 235, 121, 157, 20, 56, 82, 167, 166, 16, 230, 67,
+ 165, 70, 199, 208, 218, 220, 61, 9, 164, 111, 178, 52, 114, 133, 222,
+ 55, 166, 237, 146, 227, 102, 12, 173, 205, 205, 245, 44, 198, 76, 214,
+ 101, 223, 121, 90, 205, 122, 126, 40, 230, 86, 12, 173, 205, 53, 221,
+ 38, 114, 247, 73, 177, 183, 197, 114, 61, 226, 14, 74, 155, 203, 88,
+ 105, 109, 110, 29, 173, 46, 185, 0, 204, 135, 30, 124, 35, 238, 91,
+ 28, 252, 208, 246, 46, 209, 180, 54, 183, 244, 42, 117, 175, 30, 253,
+ 144, 244, 92, 252, 125, 234, 80, 240, 67, 53, 27, 142, 166, 181, 185,
+ 94, 99, 212, 122, 211, 16, 88, 151, 29, 95, 47, 174, 85, 173, 13,
+ 243, 161, 241, 213, 250, 210, 218, 220, 26, 191, 132, 105, 245, 181, 183,
+ 165, 54, 101, 123, 11, 251, 222, 0, 63, 244, 237, 50, 86, 155, 91,
+ 61, 159, 90, 155, 251, 16, 252, 208, 229, 254, 226, 218, 220, 23, 224,
+ 135, 174, 21, 30, 68, 107, 115, 103, 46, 103, 181, 185, 159, 154, 245,
+ 107, 115, 71, 246, 99, 181, 185, 201, 3, 88, 109, 110, 190, 112, 253,
+ 218, 220, 21, 227, 89, 109, 174, 169, 45, 171, 205, 237, 89, 65, 92,
+ 155, 251, 20, 252, 144, 215, 19, 86, 155, 187, 99, 52, 171, 205, 13,
+ 207, 212, 175, 205, 253, 181, 52, 171, 205, 181, 238, 96, 181, 185, 29,
+ 7, 232, 215, 230, 102, 174, 103, 181, 185, 167, 207, 177, 218, 220, 191,
+ 114, 235, 215, 230, 178, 179, 42, 126, 148, 86, 190, 85, 242, 196, 189,
+ 218, 92, 37, 15, 72, 114, 195, 223, 132, 123, 135, 118, 209, 203, 9,
+ 178, 218, 220, 80, 232, 235, 248, 214, 141, 250, 143, 142, 92, 190, 174,
+ 3, 87, 255, 241, 173, 113, 123, 79, 200, 151, 230, 235, 128, 70, 153,
+ 234, 17, 27, 227, 246, 158, 66, 57, 25, 56, 110, 50, 150, 132, 246,
+ 198, 237, 61, 33, 95, 167, 250, 15, 77, 134, 127, 123, 227, 246, 158,
+ 80, 239, 70, 238, 215, 154, 190, 53, 118, 191, 22, 245, 105, 228, 126,
+ 173, 127, 123, 99, 247, 107, 17, 39, 116, 239, 233, 43, 176, 131, 142,
+ 122, 152, 225, 238, 205, 133, 190, 137, 237, 220, 248, 254, 248, 55, 220,
+ 158, 205, 215, 220, 222, 83, 59, 227, 48, 131, 124, 105, 13, 32, 208,
+ 40, 83, 137, 170, 109, 141, 195, 140, 63, 39, 3, 199, 77, 198, 18,
+ 210, 214, 56, 204, 32, 95, 167, 122, 118, 77, 134, 227, 43, 227, 48,
+ 131, 122, 55, 114, 191, 22, 117, 108, 228, 126, 109, 72, 91, 99, 247,
+ 107, 81, 119, 70, 238, 215, 34, 78, 232, 222, 83, 75, 176, 131, 111,
+ 244, 48, 195, 221, 155, 219, 6, 252, 121, 136, 27, 123, 79, 109, 184,
+ 24, 208, 134, 171, 205, 109, 157, 51, 204, 236, 245, 119, 176, 24, 192,
+ 201, 112, 192, 59, 57, 52, 57, 150, 214, 57, 195, 204, 238, 233, 185,
+ 217, 189, 185, 33, 220, 56, 128, 38, 99, 73, 111, 149, 51, 204, 220,
+ 169, 187, 147, 238, 215, 134, 134, 100, 217, 123, 10, 209, 106, 115, 91,
+ 229, 12, 51, 187, 182, 176, 253, 90, 212, 123, 118, 181, 170, 168, 83,
+ 198, 219, 245, 191, 119, 206, 241, 8, 248, 161, 254, 254, 43, 63, 212,
+ 103, 118, 252, 80, 87, 255, 149, 95, 168, 128, 31, 234, 197, 93, 126,
+ 116, 110, 214, 146, 155, 155, 125, 1, 118, 240, 149, 14, 102, 248, 218,
+ 92, 232, 235, 104, 238, 198, 220, 172, 37, 103, 207, 45, 184, 185, 89,
+ 115, 3, 231, 102, 45, 56, 123, 6, 26, 101, 42, 141, 154, 27, 56,
+ 55, 227, 100, 224, 184, 201, 88, 18, 190, 52, 112, 110, 214, 60, 203,
+ 220, 76, 147, 225, 255, 165, 129, 115, 179, 230, 198, 198, 25, 83, 115,
+ 99, 227, 12, 234, 211, 200, 56, 227, 255, 165, 177, 113, 6, 113, 66,
+ 231, 102, 77, 192, 14, 90, 234, 97, 134, 157, 217, 246, 135, 190, 137,
+ 205, 220, 152, 155, 125, 193, 205, 105, 62, 231, 230, 102, 205, 12, 156,
+ 155, 125, 206, 205, 205, 128, 70, 153, 202, 220, 172, 169, 129, 115, 51,
+ 78, 6, 142, 155, 140, 37, 164, 169, 129, 115, 179, 102, 89, 230, 102,
+ 154, 12, 71, 19, 3, 231, 102, 205, 140, 93, 207, 160, 142, 141, 92,
+ 207, 132, 52, 53, 118, 61, 131, 186, 51, 114, 61, 131, 56, 161, 152,
+ 153, 49, 216, 59, 241, 11, 23, 152, 25, 56, 98, 80, 143, 238, 67,
+ 149, 26, 7, 19, 63, 111, 104, 12, 254, 188, 81, 184, 247, 213, 252,
+ 83, 210, 62, 183, 135, 200, 163, 90, 108, 181, 215, 222, 216, 215, 242,
+ 206, 220, 172, 49, 23, 3, 26, 51, 254, 22, 57, 123, 59, 56, 246,
+ 176, 248, 134, 103, 245, 122, 212, 85, 49, 227, 229, 210, 14, 156, 98,
+ 25, 39, 195, 1, 239, 228, 208, 228, 248, 75, 217, 203, 152, 218, 62,
+ 120, 195, 234, 9, 211, 234, 170, 152, 209, 151, 129, 124, 233, 56, 128,
+ 166, 99, 153, 53, 56, 91, 25, 215, 66, 170, 165, 30, 26, 26, 23,
+ 172, 98, 198, 141, 113, 52, 202, 50, 55, 107, 164, 97, 102, 70, 246,
+ 50, 46, 189, 26, 101, 254, 41, 146, 212, 179, 103, 39, 195, 170, 96,
+ 38, 67, 211, 123, 21, 165, 165, 90, 11, 229, 204, 79, 253, 55, 244,
+ 147, 41, 18, 223, 123, 137, 169, 162, 105, 61, 252, 165, 194, 31, 221,
+ 235, 168, 86, 74, 62, 252, 193, 146, 36, 181, 69, 11, 153, 180, 205,
+ 243, 252, 107, 249, 218, 202, 232, 143, 69, 62, 251, 165, 119, 15, 185,
+ 248, 191, 113, 1, 234, 211, 129, 242, 219, 106, 39, 21, 58, 223, 227,
+ 177, 242, 31, 177, 53, 106, 11, 115, 110, 19, 38, 202, 29, 187, 207,
+ 213, 218, 204, 164, 116, 141, 179, 63, 112, 207, 179, 143, 61, 25, 154,
+ 93, 24, 165, 131, 230, 253, 61, 255, 116, 165, 131, 34, 43, 211, 63,
+ 210, 211, 193, 241, 41, 39, 107, 17, 29, 204, 30, 253, 241, 199, 68,
+ 7, 185, 175, 76, 253, 88, 79, 7, 33, 213, 30, 125, 76, 116, 64,
+ 104, 212, 1, 123, 46, 214, 1, 218, 173, 158, 14, 90, 191, 163, 131,
+ 194, 154, 14, 106, 82, 126, 209, 160, 3, 203, 234, 111, 26, 102, 213,
+ 65, 41, 208, 193, 65, 123, 77, 225, 220, 34, 79, 222, 30, 114, 190,
+ 239, 2, 236, 68, 7, 139, 6, 36, 40, 116, 41, 208, 193, 196, 37,
+ 87, 197, 123, 49, 160, 131, 169, 21, 62, 167, 117, 129, 132, 70, 29,
+ 176, 231, 98, 29, 32, 174, 156, 117, 96, 229, 230, 234, 42, 173, 218,
+ 1, 211, 201, 18, 147, 3, 116, 112, 17, 116, 112, 209, 201, 14, 250,
+ 86, 177, 154, 153, 14, 84, 26, 237, 32, 223, 3, 113, 46, 23, 237,
+ 96, 44, 229, 63, 80, 62, 221, 89, 109, 239, 3, 58, 88, 27, 38,
+ 206, 33, 163, 29, 124, 228, 59, 142, 214, 186, 17, 26, 117, 192, 158,
+ 235, 172, 207, 65, 7, 244, 123, 115, 83, 6, 123, 135, 54, 17, 197,
+ 128, 58, 206, 49, 96, 58, 180, 159, 54, 88, 63, 6, 64, 59, 234,
+ 59, 167, 51, 95, 150, 49, 117, 176, 155, 49, 192, 245, 92, 0, 241,
+ 78, 125, 39, 39, 195, 1, 239, 228, 208, 228, 88, 5, 50, 156, 99,
+ 128, 107, 25, 136, 39, 58, 142, 105, 220, 56, 128, 38, 99, 241, 157,
+ 234, 110, 12, 112, 45, 3, 237, 149, 142, 131, 147, 97, 210, 100, 226,
+ 127, 19, 167, 184, 27, 3, 92, 203, 64, 123, 160, 181, 105, 83, 7,
+ 59, 213, 126, 49, 191, 105, 53, 19, 122, 66, 176, 205, 34, 242, 167,
+ 78, 181, 105, 89, 248, 49, 31, 100, 53, 19, 26, 249, 137, 124, 147,
+ 83, 109, 90, 22, 126, 12, 207, 86, 51, 161, 199, 3, 63, 17, 206,
+ 157, 238, 161, 156, 226, 204, 143, 97, 195, 106, 38, 52, 190, 159, 8,
+ 51, 252, 188, 9, 113, 66, 115, 90, 227, 193, 14, 184, 248, 252, 46,
+ 102, 234, 58, 97, 38, 113, 242, 96, 111, 255, 73, 250, 152, 193, 118,
+ 116, 29, 48, 153, 241, 79, 154, 104, 28, 102, 252, 57, 25, 137, 240,
+ 78, 137, 154, 28, 203, 68, 227, 48, 131, 124, 233, 56, 128, 38, 99,
+ 73, 159, 96, 28, 102, 252, 39, 57, 99, 6, 101, 42, 235, 244, 9,
+ 198, 97, 6, 245, 78, 108, 40, 209, 242, 177, 75, 204, 36, 172, 91,
+ 237, 54, 102, 44, 89, 248, 185, 194, 12, 242, 115, 23, 51, 168, 79,
+ 122, 159, 23, 240, 115, 133, 25, 228, 231, 46, 102, 66, 39, 56, 191,
+ 159, 43, 204, 32, 63, 119, 49, 131, 56, 161, 57, 45, 43, 216, 193,
+ 20, 17, 102, 254, 231, 132, 153, 80, 232, 235, 136, 211, 199, 12, 182,
+ 163, 49, 32, 158, 241, 143, 136, 51, 14, 51, 200, 151, 198, 0, 160,
+ 81, 166, 210, 40, 206, 56, 204, 132, 114, 50, 112, 220, 100, 44, 9,
+ 177, 198, 97, 6, 249, 58, 229, 180, 52, 25, 254, 177, 198, 97, 6,
+ 245, 158, 83, 204, 56, 229, 180, 226, 114, 142, 25, 167, 156, 86, 108,
+ 206, 49, 227, 148, 211, 138, 205, 57, 102, 156, 114, 90, 86, 134, 153,
+ 144, 63, 192, 14, 198, 139, 48, 243, 137, 115, 156, 249, 19, 48, 182,
+ 198, 141, 56, 243, 39, 231, 159, 255, 100, 252, 3, 172, 57, 195, 140,
+ 83, 222, 140, 147, 145, 8, 239, 148, 168, 201, 73, 90, 157, 51, 204,
+ 56, 141, 99, 13, 55, 14, 160, 201, 88, 44, 171, 115, 134, 25, 167,
+ 113, 172, 201, 18, 103, 214, 104, 177, 236, 143, 156, 97, 134, 172, 207,
+ 131, 52, 189, 19, 27, 178, 134, 122, 167, 189, 4, 61, 103, 93, 151,
+ 89, 146, 42, 89, 94, 214, 187, 188, 46, 187, 181, 169, 83, 77, 245,
+ 106, 103, 126, 107, 64, 167, 174, 248, 173, 153, 144, 127, 189, 59, 252,
+ 44, 28, 191, 209, 109, 188, 211, 170, 159, 78, 125, 103, 191, 100, 244,
+ 230, 74, 150, 230, 207, 130, 27, 102, 183, 110, 116, 138, 91, 127, 56,
+ 191, 31, 234, 42, 235, 26, 172, 47, 188, 95, 239, 248, 152, 108, 215,
+ 96, 78, 53, 213, 127, 112, 152, 249, 5, 108, 205, 42, 194, 204, 167,
+ 78, 152, 73, 95, 53, 216, 59, 100, 165, 62, 102, 176, 29, 173, 69,
+ 94, 197, 197, 153, 229, 238, 98, 198, 91, 215, 214, 66, 56, 25, 233,
+ 240, 78, 233, 154, 156, 132, 223, 221, 197, 140, 190, 12, 228, 75, 199,
+ 1, 52, 25, 75, 210, 82, 119, 49, 227, 198, 56, 86, 58, 99, 6,
+ 101, 42, 255, 253, 197, 93, 204, 120, 11, 49, 179, 212, 67, 213, 123,
+ 21, 165, 165, 90, 235, 230, 42, 151, 129, 103, 42, 249, 222, 165, 193,
+ 30, 235, 194, 95, 51, 46, 159, 147, 214, 58, 211, 82, 207, 190, 43,
+ 137, 156, 169, 108, 250, 222, 0, 37, 46, 249, 159, 234, 46, 237, 107,
+ 88, 176, 14, 233, 219, 13, 250, 12, 131, 191, 73, 92, 223, 140, 162,
+ 179, 164, 101, 13, 8, 86, 151, 211, 188, 73, 222, 145, 27, 224, 121,
+ 246, 88, 85, 207, 99, 238, 144, 74, 62, 41, 190, 129, 156, 49, 148,
+ 90, 250, 109, 80, 243, 7, 167, 165, 185, 161, 133, 55, 144, 190, 251,
+ 160, 207, 113, 248, 59, 199, 245, 125, 233, 125, 93, 234, 151, 92, 103,
+ 61, 57, 175, 183, 238, 253, 117, 107, 145, 202, 61, 246, 153, 84, 169,
+ 86, 42, 125, 231, 107, 208, 231, 46, 252, 61, 230, 250, 190, 145, 77,
+ 114, 7, 107, 96, 93, 114, 110, 238, 78, 13, 139, 66, 231, 202, 204,
+ 43, 119, 236, 222, 180, 46, 233, 251, 10, 251, 120, 84, 52, 229, 243,
+ 168, 200, 125, 183, 172, 144, 204, 180, 233, 71, 233, 136, 27, 37, 101,
+ 94, 207, 69, 161, 79, 105, 248, 171, 204, 245, 37, 191, 27, 218, 178,
+ 81, 191, 219, 129, 27, 219, 214, 146, 223, 237, 242, 15, 105, 31, 147,
+ 223, 109, 249, 203, 211, 181, 245, 126, 183, 95, 38, 78, 115, 249, 187,
+ 253, 50, 49, 123, 159, 72, 127, 183, 142, 193, 244, 119, 107, 95, 179,
+ 30, 253, 221, 42, 214, 175, 171, 251, 187, 249, 207, 109, 72, 127, 183,
+ 79, 174, 22, 78, 34, 191, 219, 185, 218, 62, 117, 245, 126, 55, 159,
+ 200, 246, 244, 119, 43, 187, 170, 61, 253, 221, 46, 221, 106, 255, 255,
+ 254, 187, 161, 127, 32, 191, 219, 160, 234, 174, 127, 183, 204, 63, 245,
+ 127, 183, 184, 230, 153, 150, 61, 27, 223, 79, 37, 191, 91, 72, 188,
+ 250, 29, 180, 35, 167, 187, 75, 187, 192, 207, 80, 174, 239, 177, 63,
+ 122, 142, 251, 253, 89, 82, 200, 201, 84, 123, 214, 223, 173, 208, 168,
+ 13, 210, 176, 199, 217, 199, 30, 236, 187, 125, 242, 14, 233, 151, 50,
+ 165, 131, 201, 239, 214, 246, 235, 102, 10, 221, 233, 217, 105, 201, 55,
+ 169, 127, 48, 251, 221, 204, 240, 187, 53, 131, 223, 173, 37, 237, 91,
+ 49, 239, 117, 41, 215, 248, 184, 96, 242, 187, 101, 212, 142, 80, 232,
+ 79, 199, 61, 147, 126, 153, 25, 26, 204, 126, 183, 175, 224, 119, 107,
+ 5, 191, 91, 11, 218, 247, 10, 252, 110, 77, 203, 149, 9, 38, 191,
+ 91, 155, 127, 238, 43, 239, 249, 231, 171, 188, 114, 120, 135, 89, 13,
+ 217, 239, 102, 134, 223, 173, 30, 252, 110, 31, 179, 251, 148, 178, 249,
+ 221, 198, 252, 135, 223, 13, 125, 46, 249, 221, 102, 41, 120, 123, 55,
+ 214, 170, 120, 99, 191, 99, 105, 136, 177, 117, 225, 175, 25, 151, 239,
+ 220, 2, 120, 43, 112, 44, 146, 158, 61, 247, 185, 173, 210, 149, 1,
+ 111, 222, 30, 236, 236, 121, 55, 211, 121, 192, 219, 121, 192, 219, 121,
+ 39, 188, 45, 160, 49, 126, 57, 205, 173, 22, 0, 188, 137, 98, 60,
+ 246, 125, 6, 120, 179, 206, 141, 164, 103, 177, 191, 46, 165, 206, 163,
+ 115, 3, 222, 14, 254, 203, 190, 101, 182, 15, 228, 29, 135, 95, 237,
+ 156, 233, 44, 203, 149, 2, 222, 162, 94, 141, 162, 231, 154, 103, 159,
+ 85, 247, 200, 10, 1, 222, 126, 142, 103, 125, 175, 153, 78, 195, 239,
+ 118, 6, 126, 183, 51, 12, 171, 240, 187, 253, 86, 52, 138, 158, 47,
+ 206, 223, 80, 203, 203, 2, 222, 102, 239, 101, 239, 252, 10, 199, 233,
+ 113, 1, 126, 55, 246, 206, 153, 202, 239, 102, 53, 179, 223, 77, 165,
+ 135, 40, 191, 27, 211, 115, 81, 232, 83, 26, 254, 42, 115, 125, 233,
+ 156, 230, 23, 46, 223, 180, 8, 226, 244, 31, 162, 57, 77, 61, 231,
+ 57, 205, 207, 208, 62, 209, 141, 57, 205, 207, 220, 92, 224, 103, 46,
+ 223, 180, 196, 184, 181, 115, 8, 39, 35, 29, 222, 41, 93, 147, 99,
+ 89, 98, 220, 218, 25, 249, 210, 113, 0, 77, 198, 146, 190, 216, 184,
+ 181, 115, 72, 98, 150, 57, 77, 162, 150, 111, 90, 108, 96, 190, 105,
+ 137, 193, 249, 166, 37, 6, 231, 155, 22, 27, 156, 111, 90, 108, 112,
+ 190, 105, 17, 151, 111, 250, 17, 236, 224, 23, 17, 102, 234, 59, 231,
+ 155, 160, 175, 99, 129, 27, 249, 166, 69, 92, 158, 102, 33, 183, 14,
+ 88, 96, 96, 190, 105, 33, 151, 111, 2, 26, 101, 42, 141, 22, 24,
+ 152, 111, 226, 100, 224, 184, 201, 88, 18, 126, 50, 48, 223, 180, 32,
+ 75, 190, 73, 147, 225, 255, 147, 129, 249, 166, 5, 6, 231, 155, 22,
+ 24, 156, 111, 250, 201, 224, 124, 211, 79, 6, 231, 155, 126, 100, 152,
+ 9, 253, 30, 236, 96, 145, 0, 51, 181, 3, 156, 48, 227, 15, 125,
+ 19, 231, 233, 99, 6, 219, 209, 92, 208, 124, 46, 223, 52, 47, 103,
+ 152, 57, 219, 173, 100, 29, 154, 11, 154, 207, 229, 130, 128, 70, 153,
+ 202, 25, 170, 31, 114, 134, 153, 201, 223, 140, 11, 160, 227, 224, 100,
+ 224, 184, 201, 88, 66, 126, 200, 25, 102, 30, 157, 63, 196, 206, 80,
+ 205, 115, 198, 140, 191, 38, 195, 241, 125, 206, 48, 51, 231, 195, 254,
+ 44, 223, 52, 111, 112, 182, 103, 87, 81, 167, 255, 245, 44, 44, 234,
+ 56, 59, 126, 168, 191, 255, 202, 47, 68, 192, 15, 117, 245, 95, 249,
+ 161, 238, 178, 227, 135, 122, 249, 175, 103, 117, 17, 39, 116, 255, 124,
+ 54, 216, 193, 143, 34, 204, 100, 57, 67, 53, 23, 252, 249, 119, 110,
+ 236, 159, 207, 229, 98, 192, 92, 110, 255, 124, 142, 129, 251, 231, 156,
+ 12, 7, 188, 147, 67, 147, 99, 157, 99, 224, 254, 249, 119, 220, 56,
+ 128, 38, 99, 241, 157, 99, 224, 254, 249, 119, 89, 246, 207, 191, 211,
+ 246, 207, 103, 27, 184, 127, 62, 199, 216, 56, 99, 157, 99, 108, 156,
+ 241, 157, 99, 108, 156, 65, 221, 25, 25, 103, 16, 39, 4, 51, 233,
+ 153, 96, 7, 223, 139, 48, 227, 124, 230, 36, 49, 1, 48, 246, 198,
+ 141, 125, 141, 4, 206, 63, 191, 229, 226, 76, 130, 113, 152, 65, 190,
+ 52, 206, 0, 157, 168, 241, 14, 120, 99, 28, 102, 252, 57, 25, 56,
+ 110, 50, 150, 180, 215, 198, 97, 6, 249, 58, 197, 25, 77, 70, 200,
+ 107, 227, 48, 131, 122, 55, 114, 61, 131, 58, 54, 114, 61, 131, 250,
+ 52, 114, 61, 19, 242, 218, 216, 245, 12, 226, 132, 126, 43, 246, 1,
+ 204, 105, 102, 187, 192, 204, 160, 222, 195, 187, 247, 236, 62, 52, 98,
+ 196, 48, 211, 192, 222, 97, 236, 123, 217, 208, 55, 253, 229, 96, 239,
+ 176, 176, 48, 115, 88, 88, 30, 203, 154, 102, 151, 236, 159, 95, 250,
+ 233, 221, 187, 116, 51, 185, 245, 249, 43, 198, 223, 250, 60, 123, 59,
+ 152, 112, 102, 146, 253, 113, 225, 47, 27, 138, 238, 209, 249, 169, 204,
+ 109, 250, 221, 75, 228, 75, 215, 231, 64, 163, 76, 5, 51, 79, 179,
+ 151, 177, 183, 247, 123, 182, 85, 61, 31, 11, 239, 209, 185, 121, 98,
+ 62, 149, 17, 194, 201, 192, 113, 147, 177, 56, 30, 101, 47, 227, 243,
+ 97, 37, 182, 126, 187, 196, 203, 44, 186, 71, 167, 242, 161, 85, 236,
+ 155, 228, 47, 157, 49, 19, 162, 201, 72, 120, 144, 189, 140, 82, 126,
+ 157, 204, 147, 14, 91, 133, 247, 232, 36, 189, 141, 160, 247, 232, 160,
+ 222, 249, 123, 11, 80, 143, 132, 31, 161, 27, 111, 152, 43, 177, 231,
+ 174, 115, 165, 255, 182, 170, 47, 223, 170, 116, 147, 222, 163, 67, 218,
+ 123, 217, 91, 203, 83, 99, 111, 11, 191, 135, 231, 221, 168, 157, 156,
+ 80, 207, 91, 203, 77, 126, 43, 155, 11, 238, 83, 218, 23, 179, 119,
+ 146, 155, 172, 152, 32, 236, 123, 71, 14, 149, 187, 228, 253, 137, 222,
+ 139, 210, 106, 240, 32, 133, 174, 26, 29, 38, 87, 111, 47, 254, 118,
+ 214, 213, 216, 126, 242, 145, 25, 191, 4, 145, 115, 145, 53, 186, 223,
+ 85, 232, 7, 81, 225, 178, 189, 120, 153, 134, 194, 115, 145, 177, 67,
+ 228, 33, 94, 126, 90, 155, 225, 114, 231, 153, 197, 20, 218, 35, 122,
+ 164, 220, 184, 68, 73, 97, 223, 55, 177, 99, 228, 252, 65, 37, 180,
+ 54, 145, 114, 175, 194, 106, 95, 188, 23, 165, 184, 173, 176, 78, 223,
+ 120, 185, 250, 180, 92, 90, 155, 137, 114, 212, 239, 38, 77, 238, 100,
+ 121, 105, 252, 43, 157, 239, 14, 78, 147, 67, 234, 121, 53, 164, 103,
+ 122, 53, 26, 239, 45, 96, 207, 179, 143, 211, 104, 47, 136, 33, 222,
+ 94, 16, 19, 196, 94, 8, 253, 1, 216, 11, 123, 238, 218, 94, 150,
+ 130, 189, 148, 108, 204, 206, 244, 146, 246, 69, 192, 94, 172, 189, 26,
+ 9, 199, 113, 87, 110, 39, 143, 250, 59, 130, 222, 163, 179, 241, 151,
+ 85, 42, 13, 246, 82, 237, 210, 5, 225, 111, 94, 160, 81, 168, 60,
+ 122, 243, 110, 106, 47, 141, 38, 170, 223, 16, 44, 10, 246, 114, 188,
+ 236, 10, 225, 247, 165, 238, 128, 189, 132, 109, 79, 160, 246, 146, 59,
+ 237, 128, 66, 63, 3, 123, 137, 232, 34, 214, 95, 38, 216, 203, 210,
+ 145, 175, 131, 136, 189, 52, 145, 94, 104, 223, 169, 28, 41, 223, 202,
+ 255, 36, 72, 207, 94, 6, 109, 62, 19, 68, 236, 229, 121, 165, 131,
+ 65, 234, 111, 110, 149, 139, 188, 90, 27, 164, 103, 47, 207, 58, 206,
+ 10, 34, 246, 242, 116, 198, 116, 77, 238, 100, 249, 73, 218, 20, 93,
+ 123, 233, 208, 61, 41, 136, 216, 11, 161, 209, 94, 216, 115, 177, 189,
+ 160, 63, 36, 246, 242, 20, 236, 5, 253, 27, 177, 23, 66, 183, 254,
+ 115, 174, 196, 158, 187, 182, 151, 118, 82, 125, 249, 178, 119, 222, 173,
+ 196, 94, 72, 123, 219, 214, 214, 178, 215, 182, 121, 194, 57, 102, 181,
+ 198, 237, 228, 184, 106, 31, 167, 18, 123, 57, 59, 106, 129, 178, 167,
+ 147, 23, 236, 165, 220, 240, 197, 194, 113, 52, 50, 135, 202, 215, 35,
+ 66, 130, 137, 189, 60, 171, 242, 133, 66, 15, 141, 13, 147, 35, 155,
+ 53, 14, 22, 245, 45, 26, 215, 79, 78, 255, 170, 127, 67, 98, 47,
+ 143, 182, 91, 21, 91, 27, 7, 246, 210, 52, 98, 163, 240, 236, 249,
+ 11, 176, 151, 191, 31, 125, 64, 239, 224, 73, 63, 170, 214, 239, 44,
+ 142, 26, 41, 215, 105, 187, 64, 56, 222, 17, 49, 99, 228, 227, 215,
+ 211, 233, 61, 58, 169, 239, 95, 84, 232, 208, 40, 171, 188, 178, 245,
+ 43, 97, 223, 253, 96, 47, 133, 139, 31, 165, 247, 232, 120, 14, 82,
+ 191, 17, 245, 44, 106, 178, 188, 110, 199, 118, 97, 223, 215, 96, 47,
+ 157, 87, 236, 160, 231, 229, 9, 189, 5, 236, 133, 61, 23, 219, 11,
+ 198, 54, 222, 191, 96, 172, 34, 246, 66, 232, 2, 224, 95, 216, 243,
+ 108, 236, 5, 252, 203, 194, 164, 94, 244, 188, 60, 105, 95, 17, 252,
+ 203, 141, 17, 195, 132, 107, 136, 83, 224, 95, 252, 102, 70, 209, 123,
+ 116, 70, 251, 107, 223, 1, 2, 123, 9, 235, 32, 254, 14, 208, 51,
+ 136, 71, 39, 38, 143, 165, 247, 232, 252, 252, 84, 165, 125, 208, 191,
+ 152, 197, 107, 151, 167, 224, 95, 106, 159, 138, 161, 231, 244, 175, 237,
+ 86, 233, 247, 163, 195, 229, 249, 155, 196, 103, 252, 63, 140, 27, 34,
+ 207, 49, 69, 209, 59, 120, 124, 38, 168, 123, 79, 181, 193, 191, 156,
+ 203, 59, 92, 216, 119, 21, 248, 151, 19, 91, 251, 210, 123, 116, 62,
+ 175, 172, 126, 203, 231, 14, 216, 139, 207, 189, 80, 241, 120, 193, 94,
+ 174, 127, 221, 143, 222, 163, 99, 127, 170, 229, 55, 192, 191, 204, 152,
+ 55, 80, 247, 30, 157, 158, 157, 7, 210, 218, 2, 66, 163, 127, 97,
+ 207, 197, 235, 60, 156, 167, 210, 125, 171, 43, 48, 15, 203, 20, 206,
+ 89, 157, 238, 209, 73, 200, 128, 181, 206, 61, 253, 57, 43, 182, 163,
+ 235, 163, 251, 140, 191, 239, 157, 236, 231, 97, 101, 194, 174, 219, 251,
+ 87, 92, 162, 205, 89, 125, 92, 206, 195, 70, 221, 236, 72, 235, 37,
+ 145, 47, 93, 231, 1, 141, 50, 21, 110, 183, 178, 151, 113, 164, 198,
+ 14, 219, 249, 182, 185, 181, 57, 171, 107, 25, 119, 30, 70, 179, 154,
+ 76, 78, 6, 142, 155, 140, 37, 227, 122, 246, 50, 26, 46, 121, 158,
+ 250, 252, 211, 66, 218, 156, 213, 181, 140, 67, 121, 87, 179, 117, 222,
+ 189, 44, 235, 60, 77, 70, 232, 213, 236, 101, 124, 17, 217, 217, 252,
+ 73, 53, 50, 103, 117, 45, 163, 229, 37, 117, 206, 250, 173, 167, 170,
+ 247, 42, 74, 75, 213, 71, 160, 30, 9, 63, 66, 55, 5, 31, 193,
+ 158, 187, 246, 17, 15, 193, 71, 212, 26, 58, 135, 222, 229, 71, 218,
+ 227, 93, 91, 145, 101, 90, 136, 191, 23, 9, 62, 226, 117, 211, 175,
+ 82, 136, 143, 104, 118, 234, 134, 66, 207, 7, 31, 49, 33, 164, 174,
+ 176, 239, 16, 152, 131, 172, 9, 78, 166, 115, 144, 106, 107, 213, 111,
+ 122, 158, 43, 217, 79, 46, 249, 105, 9, 225, 60, 34, 58, 223, 96,
+ 249, 155, 55, 63, 208, 187, 31, 115, 159, 235, 167, 126, 43, 49, 112,
+ 132, 220, 56, 126, 147, 112, 254, 210, 59, 109, 164, 188, 254, 228, 66,
+ 173, 205, 104, 121, 164, 237, 119, 133, 190, 16, 60, 70, 238, 185, 48,
+ 73, 216, 247, 69, 218, 88, 185, 227, 123, 151, 82, 136, 143, 88, 18,
+ 121, 88, 251, 134, 179, 85, 126, 17, 60, 37, 69, 28, 23, 226, 229,
+ 146, 77, 170, 211, 57, 136, 169, 127, 73, 117, 14, 98, 158, 36, 15,
+ 206, 44, 44, 140, 191, 111, 211, 38, 203, 249, 239, 221, 214, 190, 67,
+ 58, 85, 254, 242, 135, 154, 218, 247, 64, 167, 201, 15, 219, 92, 215,
+ 249, 30, 232, 116, 185, 195, 179, 33, 244, 30, 64, 66, 159, 27, 51,
+ 139, 123, 158, 125, 60, 66, 91, 67, 252, 241, 182, 134, 120, 34, 182,
+ 70, 104, 92, 31, 177, 231, 174, 109, 237, 14, 216, 90, 239, 173, 54,
+ 106, 107, 164, 61, 174, 143, 102, 68, 132, 137, 191, 129, 13, 182, 86,
+ 38, 113, 52, 181, 181, 60, 221, 230, 40, 116, 2, 216, 90, 253, 33,
+ 203, 133, 58, 24, 0, 182, 38, 255, 251, 34, 133, 216, 218, 230, 146,
+ 223, 43, 250, 158, 14, 182, 118, 230, 94, 71, 161, 173, 13, 6, 91,
+ 91, 85, 176, 1, 157, 179, 94, 217, 84, 87, 225, 147, 6, 182, 22,
+ 168, 243, 29, 107, 180, 181, 223, 87, 63, 165, 182, 182, 97, 134, 122,
+ 239, 37, 218, 218, 212, 13, 181, 133, 227, 125, 14, 182, 214, 43, 45,
+ 148, 222, 27, 249, 143, 173, 55, 189, 55, 242, 227, 53, 99, 108, 122,
+ 243, 221, 158, 61, 167, 179, 123, 35, 15, 253, 160, 217, 203, 36, 185,
+ 99, 174, 133, 41, 122, 182, 54, 232, 48, 185, 159, 115, 170, 252, 253,
+ 46, 139, 141, 216, 90, 74, 74, 127, 155, 158, 173, 245, 45, 60, 159,
+ 218, 26, 161, 209, 214, 216, 115, 177, 173, 161, 31, 230, 109, 13, 253,
+ 42, 177, 53, 66, 127, 6, 182, 198, 158, 187, 182, 181, 221, 96, 107,
+ 109, 98, 182, 164, 18, 91, 35, 237, 243, 227, 29, 130, 83, 87, 166,
+ 138, 215, 71, 237, 228, 129, 167, 151, 210, 185, 114, 249, 197, 139, 82,
+ 137, 173, 45, 237, 254, 131, 176, 111, 39, 176, 181, 133, 62, 211, 232,
+ 157, 147, 99, 91, 171, 237, 159, 23, 239, 39, 167, 172, 250, 77, 216,
+ 183, 58, 216, 218, 155, 58, 243, 232, 124, 247, 7, 191, 57, 10, 125,
+ 28, 108, 237, 238, 161, 4, 97, 223, 126, 96, 107, 117, 75, 37, 208,
+ 59, 39, 107, 254, 79, 165, 255, 5, 91, 123, 191, 149, 184, 111, 221,
+ 109, 99, 229, 204, 148, 185, 116, 174, 188, 249, 196, 76, 133, 126, 5,
+ 182, 86, 175, 91, 184, 176, 239, 75, 107, 188, 60, 111, 144, 143, 157,
+ 216, 218, 141, 165, 234, 119, 110, 75, 91, 38, 201, 182, 22, 237, 133,
+ 243, 251, 122, 219, 38, 203, 55, 254, 45, 155, 74, 108, 173, 119, 195,
+ 46, 10, 237, 13, 182, 182, 185, 229, 76, 161, 92, 159, 109, 211, 229,
+ 127, 159, 237, 164, 243, 108, 66, 223, 0, 91, 99, 207, 197, 182, 134,
+ 241, 152, 183, 53, 140, 175, 196, 214, 8, 221, 4, 108, 141, 61, 119,
+ 109, 107, 247, 192, 214, 2, 54, 132, 211, 121, 54, 105, 143, 49, 116,
+ 75, 200, 16, 221, 251, 42, 87, 44, 25, 78, 231, 217, 87, 103, 170,
+ 243, 242, 197, 96, 107, 143, 162, 134, 10, 251, 14, 199, 24, 90, 51,
+ 156, 206, 179, 151, 254, 161, 242, 49, 131, 95, 155, 54, 93, 124, 127,
+ 99, 119, 176, 181, 34, 139, 70, 210, 185, 114, 163, 78, 35, 20, 122,
+ 39, 216, 218, 151, 249, 71, 8, 251, 134, 129, 173, 181, 152, 50, 130,
+ 222, 87, 89, 103, 137, 74, 163, 95, 203, 191, 81, 220, 247, 37, 248,
+ 181, 220, 237, 70, 208, 121, 118, 129, 67, 42, 237, 13, 182, 86, 243,
+ 175, 81, 186, 243, 236, 57, 19, 99, 232, 60, 187, 202, 95, 42, 237,
+ 13, 126, 237, 254, 65, 241, 218, 160, 32, 216, 218, 209, 41, 68, 39,
+ 83, 101, 243, 125, 245, 44, 90, 49, 176, 181, 166, 237, 196, 223, 174,
+ 244, 4, 91, 235, 86, 143, 205, 209, 9, 125, 22, 108, 141, 61, 23,
+ 207, 209, 113, 94, 78, 230, 232, 1, 23, 129, 126, 160, 55, 71, 103,
+ 247, 246, 133, 66, 95, 199, 37, 253, 57, 58, 182, 163, 123, 139, 151,
+ 185, 115, 50, 151, 220, 205, 43, 103, 179, 79, 82, 207, 171, 33, 221,
+ 91, 188, 204, 237, 45, 2, 141, 50, 149, 70, 151, 220, 205, 43, 187,
+ 150, 129, 185, 20, 58, 14, 78, 6, 142, 155, 140, 37, 193, 225, 110,
+ 94, 217, 181, 12, 92, 127, 211, 113, 92, 202, 114, 78, 70, 147, 145,
+ 116, 209, 221, 188, 178, 107, 25, 184, 102, 163, 231, 100, 46, 101, 169,
+ 215, 165, 249, 69, 171, 153, 208, 120, 247, 163, 40, 239, 232, 244, 29,
+ 200, 44, 252, 88, 254, 201, 106, 38, 52, 242, 19, 229, 165, 156, 190,
+ 3, 233, 112, 230, 199, 242, 19, 86, 51, 161, 145, 159, 40, 111, 225,
+ 84, 3, 115, 209, 153, 31, 91, 191, 90, 205, 132, 70, 126, 162, 117,
+ 45, 191, 23, 163, 224, 68, 227, 151, 113, 6, 236, 224, 138, 30, 102,
+ 216, 189, 125, 73, 23, 6, 123, 7, 156, 215, 199, 12, 182, 35, 118,
+ 16, 112, 129, 241, 79, 59, 231, 238, 186, 54, 27, 123, 134, 185, 53,
+ 145, 17, 192, 201, 72, 130, 119, 74, 210, 228, 132, 156, 115, 119, 93,
+ 235, 90, 6, 206, 169, 232, 56, 206, 115, 227, 0, 154, 140, 197, 113,
+ 214, 221, 117, 173, 107, 25, 24, 75, 233, 56, 206, 59, 99, 6, 101,
+ 42, 254, 229, 172, 187, 235, 90, 215, 50, 208, 135, 210, 253, 193, 115,
+ 89, 108, 156, 174, 81, 192, 198, 53, 250, 69, 35, 176, 113, 193, 218,
+ 197, 105, 127, 48, 11, 63, 54, 15, 181, 154, 9, 141, 252, 68, 243,
+ 83, 167, 115, 45, 103, 157, 249, 177, 185, 134, 213, 76, 104, 228, 39,
+ 154, 131, 240, 252, 34, 178, 240, 99, 241, 196, 106, 38, 52, 242, 19,
+ 197, 25, 30, 51, 136, 19, 130, 153, 164, 147, 96, 7, 23, 245, 48,
+ 195, 238, 237, 139, 128, 190, 25, 167, 244, 49, 131, 237, 136, 29, 100,
+ 156, 230, 246, 47, 79, 25, 23, 103, 144, 47, 145, 17, 1, 52, 202,
+ 84, 242, 77, 167, 140, 139, 51, 17, 156, 12, 28, 55, 25, 75, 226,
+ 63, 198, 197, 25, 228, 203, 99, 38, 66, 147, 17, 240, 143, 113, 113,
+ 6, 245, 206, 127, 175, 202, 85, 156, 193, 239, 85, 185, 27, 103, 124,
+ 179, 240, 115, 21, 103, 144, 159, 187, 113, 6, 245, 73, 249, 229, 137,
+ 76, 117, 21, 103, 252, 129, 159, 187, 113, 38, 224, 31, 231, 247, 115,
+ 21, 103, 240, 253, 220, 141, 51, 136, 19, 130, 153, 136, 163, 96, 7,
+ 103, 244, 48, 195, 238, 237, 11, 128, 190, 73, 199, 245, 49, 131, 237,
+ 104, 12, 56, 193, 248, 91, 142, 27, 23, 103, 144, 47, 141, 1, 64,
+ 163, 76, 108, 147, 126, 204, 184, 56, 19, 192, 201, 192, 113, 147, 177,
+ 132, 30, 51, 46, 206, 32, 95, 30, 51, 1, 154, 140, 140, 163, 198,
+ 197, 25, 212, 59, 181, 161, 183, 105, 193, 174, 226, 140, 105, 212, 5,
+ 179, 187, 113, 6, 117, 204, 243, 115, 21, 103, 144, 159, 187, 113, 38,
+ 148, 231, 119, 40, 45, 216, 85, 156, 177, 134, 93, 48, 187, 27, 103,
+ 80, 119, 148, 223, 203, 180, 96, 87, 113, 198, 50, 226, 130, 217, 221,
+ 56, 131, 56, 161, 123, 14, 7, 193, 14, 78, 234, 97, 230, 83, 250,
+ 123, 100, 28, 1, 127, 158, 174, 143, 25, 108, 71, 99, 192, 17, 174,
+ 86, 230, 176, 113, 113, 38, 130, 147, 145, 1, 239, 148, 161, 201, 177,
+ 28, 54, 46, 206, 32, 95, 58, 14, 160, 201, 88, 210, 15, 25, 23,
+ 103, 34, 210, 157, 49, 131, 50, 21, 92, 30, 50, 46, 206, 160, 222,
+ 115, 26, 103, 248, 243, 142, 150, 195, 57, 143, 51, 60, 63, 212, 103,
+ 78, 227, 12, 207, 47, 244, 80, 206, 227, 140, 83, 14, 224, 32, 87,
+ 43, 179, 23, 236, 224, 168, 30, 102, 184, 187, 32, 160, 175, 99, 191,
+ 27, 57, 128, 131, 220, 218, 249, 0, 151, 3, 216, 111, 92, 156, 65,
+ 190, 52, 7, 0, 52, 202, 84, 26, 237, 55, 46, 206, 132, 114, 50,
+ 112, 220, 100, 44, 9, 251, 140, 139, 51, 200, 215, 41, 7, 160, 201,
+ 240, 223, 103, 92, 156, 65, 189, 231, 52, 206, 240, 54, 105, 218, 159,
+ 243, 56, 195, 243, 67, 125, 230, 52, 206, 240, 252, 252, 247, 229, 60,
+ 206, 240, 152, 65, 156, 208, 90, 153, 93, 96, 7, 7, 245, 48, 195,
+ 221, 5, 1, 125, 19, 119, 235, 99, 6, 219, 209, 61, 225, 61, 220,
+ 25, 230, 221, 57, 139, 51, 252, 121, 76, 228, 75, 247, 182, 129, 70,
+ 153, 74, 158, 225, 239, 156, 197, 25, 254, 60, 166, 63, 39, 3, 199,
+ 77, 198, 18, 242, 119, 206, 226, 12, 127, 30, 19, 249, 58, 237, 109,
+ 107, 50, 28, 187, 114, 22, 103, 200, 121, 204, 32, 77, 239, 244, 158,
+ 239, 139, 5, 183, 162, 158, 179, 158, 199, 244, 191, 178, 204, 92, 185,
+ 244, 158, 108, 207, 215, 57, 157, 57, 254, 155, 227, 183, 183, 224, 86,
+ 212, 105, 214, 243, 122, 25, 142, 101, 230, 78, 19, 39, 186, 197, 47,
+ 132, 227, 151, 56, 162, 252, 86, 212, 97, 214, 243, 92, 105, 211, 86,
+ 152, 151, 127, 60, 59, 213, 29, 126, 168, 59, 138, 153, 214, 133, 182,
+ 166, 219, 122, 189, 115, 222, 39, 228, 222, 50, 243, 200, 97, 195, 204,
+ 34, 126, 180, 86, 102, 23, 87, 43, 179, 13, 236, 96, 175, 30, 102,
+ 184, 187, 32, 118, 130, 63, 223, 161, 143, 25, 108, 71, 99, 192, 78,
+ 174, 86, 102, 123, 206, 226, 12, 127, 30, 36, 148, 147, 225, 128, 119,
+ 114, 104, 114, 172, 219, 115, 22, 103, 248, 243, 32, 200, 151, 142, 3,
+ 104, 50, 22, 223, 237, 57, 139, 51, 252, 121, 144, 208, 29, 89, 106,
+ 101, 118, 104, 121, 134, 109, 57, 139, 51, 228, 60, 72, 144, 166, 119,
+ 250, 125, 159, 212, 130, 91, 215, 108, 59, 242, 206, 121, 16, 199, 197,
+ 101, 230, 168, 189, 117, 108, 238, 216, 164, 149, 227, 103, 217, 86, 112,
+ 107, 207, 197, 97, 239, 236, 249, 251, 3, 102, 218, 220, 140, 117, 139,
+ 159, 47, 199, 47, 241, 203, 66, 91, 23, 95, 158, 241, 206, 190, 174,
+ 227, 238, 50, 243, 210, 70, 235, 221, 194, 12, 234, 142, 242, 59, 83,
+ 112, 107, 80, 167, 145, 239, 236, 221, 37, 93, 94, 102, 190, 189, 103,
+ 176, 91, 152, 65, 156, 80, 204, 164, 130, 29, 236, 210, 193, 12, 119,
+ 23, 68, 98, 26, 96, 44, 85, 31, 51, 216, 142, 250, 231, 173, 140,
+ 255, 158, 201, 159, 187, 25, 103, 138, 184, 180, 131, 136, 30, 149, 183,
+ 80, 25, 91, 185, 56, 3, 52, 202, 84, 226, 196, 223, 69, 114, 185,
+ 23, 103, 92, 203, 8, 121, 156, 212, 128, 198, 25, 78, 6, 142, 155,
+ 140, 229, 243, 205, 205, 221, 140, 51, 174, 101, 212, 158, 158, 196, 206,
+ 130, 165, 102, 137, 51, 68, 198, 169, 236, 199, 225, 28, 103, 92, 203,
+ 216, 156, 17, 163, 96, 166, 158, 151, 170, 247, 42, 74, 75, 147, 105,
+ 118, 141, 15, 211, 80, 143, 132, 31, 161, 241, 59, 29, 236, 185, 106,
+ 59, 13, 76, 37, 157, 246, 127, 119, 180, 206, 180, 200, 95, 84, 165,
+ 119, 102, 159, 27, 49, 77, 161, 111, 71, 132, 73, 127, 61, 223, 35,
+ 60, 3, 158, 103, 202, 2, 137, 197, 183, 229, 180, 198, 160, 78, 244,
+ 74, 73, 20, 223, 148, 125, 201, 184, 213, 82, 242, 163, 10, 90, 155,
+ 36, 105, 127, 254, 79, 26, 168, 231, 145, 214, 73, 93, 218, 230, 23,
+ 158, 197, 41, 31, 183, 81, 10, 89, 58, 155, 222, 153, 93, 225, 167,
+ 59, 54, 245, 156, 101, 178, 180, 97, 127, 37, 187, 168, 239, 79, 177,
+ 118, 105, 79, 106, 172, 214, 38, 77, 218, 125, 96, 188, 93, 61, 103,
+ 185, 93, 66, 123, 21, 245, 61, 17, 187, 75, 90, 178, 184, 190, 214,
+ 102, 143, 180, 54, 185, 162, 93, 61, 103, 185, 79, 242, 57, 157, 95,
+ 216, 215, 39, 238, 160, 212, 254, 223, 146, 90, 155, 116, 233, 155, 47,
+ 189, 213, 179, 6, 209, 71, 165, 216, 144, 91, 194, 241, 158, 141, 61,
+ 33, 5, 214, 251, 134, 222, 153, 61, 165, 126, 144, 66, 231, 143, 62,
+ 35, 221, 14, 172, 40, 236, 251, 52, 246, 188, 212, 182, 219, 50, 122,
+ 103, 246, 217, 37, 59, 20, 250, 85, 212, 101, 105, 211, 197, 139, 194,
+ 190, 120, 103, 182, 229, 147, 123, 90, 155, 155, 210, 135, 141, 30, 105,
+ 231, 120, 110, 75, 69, 218, 60, 23, 246, 53, 197, 221, 149, 174, 36,
+ 60, 210, 218, 100, 72, 251, 54, 95, 87, 207, 75, 69, 63, 148, 22,
+ 56, 78, 235, 200, 125, 34, 157, 136, 252, 75, 107, 243, 92, 58, 125,
+ 86, 187, 83, 60, 250, 165, 148, 209, 96, 145, 176, 175, 71, 220, 107,
+ 201, 81, 105, 41, 105, 35, 55, 79, 248, 78, 61, 19, 104, 246, 144,
+ 39, 100, 198, 137, 229, 166, 121, 202, 213, 126, 39, 119, 69, 123, 201,
+ 27, 43, 189, 167, 142, 215, 156, 91, 222, 34, 191, 74, 17, 218, 243,
+ 182, 60, 114, 173, 182, 221, 180, 190, 121, 229, 82, 109, 2, 20, 186,
+ 144, 57, 159, 60, 172, 133, 135, 80, 238, 243, 52, 31, 185, 111, 224,
+ 34, 237, 76, 224, 123, 242, 255, 164, 42, 10, 46, 30, 71, 21, 148,
+ 205, 150, 21, 66, 28, 189, 142, 45, 44, 179, 218, 30, 63, 74, 111,
+ 121, 84, 76, 214, 171, 249, 33, 190, 4, 253, 43, 239, 75, 208, 95,
+ 210, 220, 136, 70, 163, 47, 97, 207, 93, 251, 146, 237, 224, 75, 122,
+ 6, 29, 14, 36, 190, 164, 72, 211, 26, 138, 252, 154, 67, 194, 164,
+ 208, 204, 8, 225, 187, 252, 5, 190, 132, 205, 109, 151, 211, 250, 147,
+ 66, 224, 75, 68, 115, 91, 69, 127, 177, 171, 165, 71, 55, 223, 6,
+ 18, 95, 242, 253, 93, 245, 46, 143, 87, 81, 235, 164, 152, 31, 163,
+ 235, 139, 109, 109, 163, 84, 179, 177, 103, 10, 241, 37, 81, 237, 99,
+ 85, 26, 124, 201, 204, 233, 219, 82, 196, 186, 183, 75, 87, 190, 243,
+ 161, 247, 94, 159, 140, 204, 175, 217, 248, 118, 9, 227, 146, 168, 175,
+ 87, 220, 46, 233, 246, 194, 11, 41, 196, 151, 68, 122, 70, 164, 168,
+ 231, 204, 247, 73, 95, 150, 202, 159, 44, 150, 123, 80, 250, 227, 220,
+ 161, 64, 226, 75, 58, 158, 254, 80, 209, 207, 155, 168, 163, 82, 106,
+ 163, 161, 58, 186, 58, 33, 213, 172, 65, 106, 166, 78, 73, 111, 146,
+ 215, 107, 125, 207, 72, 83, 91, 236, 18, 246, 125, 3, 190, 164, 106,
+ 229, 191, 131, 136, 47, 217, 123, 126, 183, 86, 199, 114, 89, 26, 48,
+ 111, 175, 78, 223, 107, 210, 225, 26, 187, 131, 136, 47, 41, 56, 123,
+ 103, 16, 241, 37, 45, 159, 111, 211, 233, 123, 87, 106, 184, 52, 37,
+ 136, 248, 18, 239, 85, 91, 52, 185, 15, 165, 163, 107, 55, 233, 244,
+ 125, 34, 213, 140, 39, 109, 158, 75, 91, 126, 222, 162, 201, 125, 41,
+ 53, 75, 75, 17, 246, 125, 27, 251, 90, 122, 85, 147, 198, 49, 185,
+ 234, 7, 105, 218, 185, 87, 15, 185, 73, 245, 205, 98, 185, 224, 75,
+ 236, 210, 119, 65, 196, 151, 36, 183, 85, 227, 170, 9, 124, 201, 142,
+ 222, 241, 98, 185, 105, 121, 228, 79, 190, 39, 117, 74, 121, 229, 225,
+ 251, 102, 171, 227, 5, 95, 178, 254, 237, 28, 157, 190, 62, 242, 140,
+ 244, 25, 65, 196, 151, 60, 49, 205, 212, 198, 91, 80, 222, 217, 125,
+ 166, 142, 174, 10, 203, 172, 238, 203, 143, 210, 155, 193, 151, 232, 213,
+ 131, 17, 95, 130, 243, 40, 226, 75, 58, 124, 240, 97, 26, 206, 139,
+ 136, 47, 33, 244, 124, 240, 37, 236, 57, 241, 37, 197, 157, 248, 133,
+ 180, 205, 180, 132, 22, 61, 108, 39, 190, 164, 166, 199, 103, 202, 220,
+ 186, 183, 28, 38, 93, 216, 62, 81, 120, 126, 178, 173, 215, 2, 137,
+ 173, 107, 151, 211, 218, 36, 219, 252, 149, 146, 104, 93, 139, 125, 63,
+ 30, 187, 90, 234, 153, 158, 102, 39, 190, 228, 200, 212, 122, 10, 206,
+ 154, 14, 95, 39, 249, 62, 254, 187, 161, 168, 239, 150, 241, 27, 165,
+ 15, 255, 173, 25, 76, 124, 73, 174, 80, 171, 66, 143, 141, 73, 150,
+ 234, 21, 89, 21, 44, 234, 59, 37, 220, 46, 21, 169, 243, 58, 152,
+ 248, 146, 54, 191, 120, 40, 115, 255, 146, 147, 182, 75, 56, 247, 20,
+ 245, 237, 99, 221, 37, 253, 240, 227, 223, 193, 196, 151, 196, 253, 182,
+ 76, 161, 3, 199, 237, 147, 102, 220, 152, 44, 148, 59, 16, 230, 37,
+ 125, 147, 58, 208, 239, 220, 245, 31, 93, 81, 161, 127, 6, 95, 178,
+ 40, 250, 164, 112, 188, 115, 198, 158, 144, 130, 71, 215, 165, 190, 228,
+ 158, 79, 128, 226, 183, 226, 98, 206, 72, 141, 146, 155, 9, 253, 223,
+ 45, 235, 121, 41, 170, 81, 239, 134, 196, 151, 204, 190, 241, 155, 122,
+ 166, 40, 242, 178, 228, 99, 58, 45, 148, 219, 27, 124, 73, 191, 93,
+ 175, 27, 18, 95, 82, 98, 80, 62, 229, 157, 183, 70, 221, 150, 206,
+ 60, 42, 42, 28, 239, 93, 240, 37, 35, 110, 151, 164, 223, 230, 187,
+ 100, 47, 174, 208, 18, 248, 146, 42, 179, 223, 23, 246, 237, 23, 247,
+ 68, 234, 218, 210, 39, 152, 248, 146, 78, 166, 103, 202, 59, 76, 6,
+ 95, 178, 163, 163, 248, 157, 243, 195, 188, 228, 147, 7, 137, 164, 141,
+ 252, 145, 105, 136, 66, 191, 13, 246, 144, 79, 149, 241, 23, 246, 45,
+ 182, 205, 83, 190, 122, 118, 10, 245, 37, 205, 62, 154, 172, 196, 138,
+ 218, 224, 75, 110, 148, 56, 36, 212, 243, 40, 152, 151, 244, 249, 169,
+ 149, 157, 248, 146, 66, 125, 127, 81, 232, 209, 224, 75, 58, 254, 121,
+ 94, 56, 103, 221, 12, 190, 164, 213, 130, 242, 169, 196, 151, 220, 146,
+ 205, 10, 221, 17, 230, 37, 95, 12, 139, 22, 226, 232, 37, 248, 18,
+ 86, 19, 232, 71, 233, 83, 224, 75, 244, 106, 5, 169, 47, 57, 197,
+ 230, 37, 243, 97, 94, 130, 235, 31, 226, 75, 8, 253, 57, 248, 18,
+ 246, 156, 248, 146, 30, 78, 252, 94, 192, 188, 100, 224, 176, 24, 250,
+ 45, 194, 77, 199, 212, 58, 174, 147, 131, 195, 164, 9, 23, 70, 9,
+ 177, 53, 121, 194, 2, 137, 229, 180, 150, 211, 186, 181, 107, 48, 47,
+ 17, 229, 180, 20, 95, 108, 93, 45, 221, 234, 74, 238, 103, 73, 146,
+ 106, 191, 85, 223, 161, 51, 172, 113, 112, 173, 39, 234, 187, 41, 126,
+ 163, 84, 167, 51, 233, 187, 89, 250, 123, 163, 250, 158, 165, 173, 201,
+ 146, 127, 238, 33, 194, 190, 225, 209, 118, 41, 166, 90, 23, 51, 241,
+ 37, 209, 101, 59, 43, 116, 9, 235, 118, 9, 215, 153, 162, 190, 135,
+ 192, 151, 140, 218, 49, 192, 76, 124, 73, 158, 63, 84, 89, 103, 35,
+ 247, 73, 249, 103, 137, 117, 53, 11, 230, 37, 91, 166, 142, 165, 223,
+ 94, 188, 255, 163, 250, 29, 198, 51, 224, 75, 150, 47, 143, 22, 246,
+ 189, 15, 243, 146, 207, 19, 201, 111, 116, 74, 186, 242, 175, 86, 179,
+ 7, 107, 156, 212, 210, 98, 93, 189, 133, 121, 201, 5, 250, 251, 58,
+ 164, 207, 61, 99, 180, 59, 229, 47, 75, 235, 18, 196, 114, 95, 131,
+ 47, 9, 56, 65, 206, 214, 222, 148, 110, 71, 71, 105, 114, 111, 75,
+ 191, 85, 143, 50, 235, 205, 75, 126, 191, 29, 73, 191, 23, 89, 89,
+ 251, 174, 101, 46, 240, 37, 191, 20, 143, 210, 121, 231, 39, 210, 237,
+ 249, 164, 205, 115, 105, 180, 103, 180, 153, 204, 75, 242, 12, 212, 123,
+ 231, 215, 82, 80, 121, 106, 243, 114, 234, 16, 141, 134, 121, 137, 101,
+ 103, 140, 88, 46, 204, 75, 90, 190, 136, 161, 223, 169, 156, 245, 72,
+ 211, 21, 248, 146, 35, 119, 197, 125, 113, 141, 51, 246, 40, 105, 147,
+ 87, 14, 171, 164, 210, 121, 192, 151, 180, 26, 46, 126, 231, 60, 219,
+ 124, 228, 230, 121, 200, 120, 223, 147, 191, 24, 162, 98, 176, 8, 204,
+ 75, 202, 55, 27, 109, 22, 175, 233, 10, 203, 172, 94, 212, 143, 210,
+ 56, 47, 209, 171, 35, 165, 57, 178, 84, 110, 255, 50, 101, 176, 183,
+ 255, 54, 189, 28, 25, 171, 51, 76, 180, 67, 123, 155, 27, 57, 50,
+ 59, 151, 191, 178, 51, 254, 155, 63, 127, 47, 151, 123, 121, 101, 215,
+ 121, 159, 14, 49, 5, 105, 142, 204, 159, 147, 145, 8, 239, 148, 168,
+ 201, 241, 111, 153, 189, 12, 231, 188, 178, 107, 25, 5, 191, 89, 155,
+ 76, 199, 97, 227, 198, 1, 52, 25, 75, 117, 255, 174, 110, 230, 149,
+ 93, 203, 24, 112, 103, 61, 171, 101, 180, 101, 249, 78, 190, 77, 219,
+ 35, 173, 220, 213, 205, 188, 178, 107, 25, 21, 184, 28, 25, 234, 157,
+ 196, 15, 19, 196, 15, 212, 35, 221, 191, 212, 232, 10, 16, 63, 216,
+ 115, 213, 118, 170, 155, 74, 57, 251, 226, 150, 153, 150, 27, 101, 143,
+ 208, 185, 232, 175, 245, 206, 42, 244, 117, 88, 215, 222, 148, 174, 11,
+ 99, 232, 123, 83, 23, 72, 44, 159, 189, 156, 214, 52, 190, 137, 90,
+ 41, 137, 242, 217, 42, 206, 87, 75, 190, 82, 21, 27, 137, 31, 62,
+ 55, 203, 105, 249, 151, 117, 146, 247, 172, 18, 226, 122, 38, 88, 215,
+ 190, 191, 176, 60, 205, 145, 45, 106, 90, 67, 235, 155, 44, 85, 123,
+ 80, 71, 167, 6, 203, 46, 229, 58, 255, 5, 93, 215, 230, 233, 161,
+ 230, 158, 252, 96, 93, 27, 118, 163, 135, 176, 111, 47, 88, 215, 142,
+ 77, 251, 205, 70, 226, 135, 61, 92, 125, 207, 125, 176, 174, 45, 189,
+ 227, 159, 6, 194, 119, 182, 30, 148, 230, 95, 168, 219, 144, 196, 143,
+ 3, 27, 26, 41, 116, 203, 232, 163, 210, 228, 137, 109, 133, 231, 50,
+ 190, 131, 248, 49, 242, 248, 18, 58, 23, 173, 125, 102, 136, 66, 63,
+ 133, 117, 237, 171, 146, 149, 133, 103, 48, 238, 67, 252, 184, 179, 118,
+ 11, 93, 215, 62, 120, 255, 176, 66, 103, 70, 93, 150, 164, 49, 87,
+ 117, 190, 177, 112, 77, 42, 222, 246, 31, 186, 174, 189, 63, 254, 44,
+ 93, 215, 254, 253, 215, 69, 157, 190, 119, 37, 71, 220, 3, 186, 174,
+ 221, 62, 254, 126, 16, 201, 145, 253, 58, 241, 174, 176, 175, 39, 204,
+ 69, 131, 71, 159, 167, 235, 218, 181, 53, 212, 117, 106, 30, 136, 31,
+ 151, 206, 172, 19, 246, 197, 248, 209, 181, 251, 100, 186, 174, 173, 210,
+ 163, 83, 16, 137, 31, 39, 61, 170, 138, 223, 25, 226, 135, 207, 149,
+ 196, 64, 18, 63, 82, 95, 239, 10, 84, 235, 88, 114, 203, 94, 37,
+ 255, 21, 222, 59, 252, 2, 214, 181, 79, 204, 108, 93, 187, 247, 214,
+ 92, 133, 206, 13, 241, 99, 238, 119, 63, 234, 212, 145, 250, 200, 71,
+ 46, 53, 164, 235, 218, 213, 155, 212, 124, 207, 91, 152, 139, 134, 22,
+ 24, 94, 95, 172, 231, 194, 50, 171, 37, 246, 163, 52, 230, 200, 244,
+ 106, 140, 137, 47, 65, 255, 74, 124, 9, 126, 135, 30, 253, 37, 241,
+ 37, 132, 54, 131, 47, 97, 207, 179, 241, 37, 48, 23, 141, 29, 58,
+ 208, 70, 124, 137, 247, 233, 169, 10, 109, 1, 95, 114, 182, 219, 207,
+ 226, 92, 238, 148, 5, 18, 219, 203, 90, 78, 107, 86, 61, 97, 46,
+ 42, 218, 203, 82, 253, 193, 106, 233, 198, 192, 41, 212, 151, 28, 177,
+ 206, 85, 232, 220, 224, 75, 14, 206, 93, 34, 196, 116, 190, 184, 141,
+ 210, 237, 192, 253, 212, 151, 252, 30, 184, 70, 251, 70, 79, 178, 20,
+ 88, 127, 182, 176, 239, 57, 240, 37, 3, 109, 177, 13, 136, 47, 105,
+ 82, 33, 116, 139, 186, 222, 218, 46, 93, 217, 191, 37, 89, 212, 55,
+ 45, 118, 151, 84, 245, 135, 189, 212, 151, 36, 237, 113, 104, 121, 239,
+ 125, 82, 243, 23, 207, 132, 114, 243, 194, 186, 246, 203, 37, 100, 92,
+ 233, 82, 187, 222, 95, 105, 227, 61, 42, 173, 41, 186, 95, 88, 71,
+ 122, 5, 124, 137, 231, 189, 55, 129, 196, 151, 60, 127, 113, 66, 161,
+ 63, 133, 185, 232, 55, 94, 171, 133, 54, 126, 1, 124, 201, 163, 126,
+ 29, 104, 190, 189, 123, 147, 197, 10, 125, 19, 124, 73, 211, 35, 135,
+ 133, 239, 252, 12, 124, 201, 200, 181, 103, 104, 190, 125, 228, 246, 243,
+ 52, 223, 30, 126, 204, 97, 211, 243, 37, 103, 222, 238, 163, 249, 246,
+ 57, 237, 118, 218, 72, 142, 172, 229, 10, 187, 78, 223, 39, 82, 235,
+ 219, 54, 154, 111, 223, 16, 186, 197, 70, 230, 162, 37, 254, 217, 40,
+ 236, 107, 130, 117, 109, 141, 101, 235, 105, 190, 253, 222, 235, 101, 54,
+ 146, 35, 251, 173, 221, 66, 155, 158, 47, 41, 244, 225, 24, 154, 111,
+ 127, 61, 180, 175, 141, 228, 200, 76, 201, 237, 117, 234, 117, 243, 200,
+ 189, 34, 251, 210, 124, 251, 139, 203, 253, 109, 36, 71, 54, 243, 139,
+ 65, 54, 61, 95, 114, 250, 127, 4, 131, 239, 201, 5, 222, 14, 178,
+ 145, 28, 217, 136, 239, 134, 216, 244, 124, 9, 171, 21, 247, 163, 52,
+ 206, 69, 245, 106, 200, 137, 47, 193, 121, 20, 241, 37, 54, 240, 37,
+ 56, 47, 34, 190, 132, 208, 85, 193, 151, 176, 231, 196, 151, 148, 112,
+ 226, 55, 31, 124, 137, 87, 239, 43, 116, 94, 178, 254, 171, 42, 202,
+ 186, 250, 71, 88, 215, 126, 177, 161, 139, 112, 141, 189, 10, 214, 181,
+ 108, 31, 123, 57, 173, 73, 190, 0, 190, 68, 180, 143, 141, 125, 11,
+ 196, 175, 150, 182, 21, 77, 75, 37, 190, 164, 215, 147, 131, 10, 253,
+ 101, 204, 58, 169, 228, 213, 179, 194, 179, 86, 119, 193, 151, 180, 14,
+ 242, 216, 74, 124, 201, 216, 133, 143, 149, 246, 111, 103, 37, 75, 143,
+ 190, 185, 46, 236, 187, 111, 188, 93, 186, 209, 99, 113, 42, 241, 37,
+ 59, 54, 116, 87, 232, 74, 224, 75, 154, 213, 203, 35, 236, 59, 126,
+ 194, 46, 41, 169, 201, 77, 234, 75, 166, 191, 63, 69, 153, 79, 44,
+ 137, 218, 39, 173, 253, 177, 170, 240, 59, 64, 107, 6, 28, 148, 130,
+ 207, 255, 70, 115, 100, 99, 218, 109, 86, 232, 123, 99, 143, 74, 183,
+ 223, 223, 39, 236, 59, 215, 122, 66, 58, 112, 116, 105, 48, 241, 37,
+ 230, 66, 243, 21, 122, 18, 204, 75, 186, 124, 61, 77, 216, 55, 32,
+ 254, 188, 36, 143, 142, 15, 38, 190, 100, 223, 228, 126, 10, 93, 53,
+ 230, 178, 52, 44, 119, 11, 97, 223, 55, 209, 215, 164, 99, 126, 36,
+ 87, 117, 83, 74, 90, 252, 82, 25, 239, 202, 168, 219, 82, 250, 39,
+ 151, 132, 115, 169, 137, 224, 75, 78, 7, 189, 79, 115, 100, 7, 51,
+ 84, 186, 11, 248, 146, 45, 75, 139, 9, 229, 214, 135, 121, 73, 159,
+ 106, 158, 52, 71, 118, 111, 215, 117, 69, 86, 67, 240, 37, 243, 62,
+ 219, 43, 148, 27, 12, 190, 164, 102, 202, 18, 154, 35, 123, 47, 100,
+ 168, 66, 251, 131, 47, 25, 94, 170, 138, 176, 239, 123, 219, 60, 229,
+ 110, 7, 194, 104, 142, 108, 253, 237, 135, 138, 143, 47, 7, 190, 164,
+ 230, 163, 59, 66, 76, 143, 134, 117, 237, 151, 109, 218, 211, 28, 89,
+ 245, 124, 191, 43, 244, 56, 240, 37, 150, 31, 28, 194, 58, 240, 95,
+ 113, 239, 238, 64, 5, 154, 35, 43, 218, 215, 162, 214, 159, 71, 22,
+ 148, 231, 15, 143, 18, 218, 228, 85, 240, 37, 236, 91, 0, 126, 148,
+ 62, 14, 190, 68, 239, 27, 1, 196, 151, 224, 122, 137, 248, 146, 185,
+ 224, 75, 42, 112, 57, 50, 66, 227, 222, 93, 133, 44, 57, 178, 234,
+ 166, 8, 39, 126, 123, 192, 151, 248, 53, 137, 162, 57, 50, 191, 178,
+ 234, 250, 252, 85, 68, 152, 84, 115, 187, 120, 125, 94, 19, 230, 37,
+ 236, 12, 203, 114, 90, 115, 94, 19, 124, 137, 232, 12, 11, 246, 149,
+ 227, 86, 75, 147, 251, 15, 162, 57, 178, 85, 33, 234, 247, 135, 66,
+ 96, 94, 82, 226, 211, 62, 194, 115, 150, 79, 96, 141, 211, 170, 94,
+ 87, 154, 35, 203, 157, 174, 126, 235, 104, 149, 53, 89, 26, 217, 191,
+ 167, 176, 111, 51, 171, 93, 122, 94, 104, 56, 205, 145, 13, 91, 163,
+ 214, 84, 111, 139, 220, 46, 201, 77, 197, 245, 216, 111, 97, 94, 82,
+ 249, 172, 149, 230, 200, 134, 182, 81, 219, 215, 141, 217, 39, 141, 250,
+ 55, 82, 216, 119, 43, 172, 113, 254, 55, 38, 130, 230, 200, 34, 98,
+ 212, 26, 248, 199, 81, 71, 165, 13, 19, 197, 231, 74, 207, 193, 188,
+ 228, 219, 126, 67, 105, 142, 172, 88, 127, 245, 253, 111, 131, 47, 249,
+ 173, 255, 72, 157, 119, 62, 47, 205, 90, 56, 138, 230, 200, 78, 149,
+ 27, 163, 229, 170, 46, 75, 21, 127, 30, 43, 236, 123, 3, 230, 37,
+ 51, 90, 176, 28, 217, 196, 43, 42, 253, 6, 124, 201, 232, 177, 226,
+ 251, 167, 51, 193, 151, 124, 86, 44, 138, 230, 200, 26, 21, 100, 57,
+ 178, 214, 121, 162, 116, 222, 249, 137, 148, 118, 144, 229, 200, 242, 52,
+ 136, 214, 114, 115, 47, 165, 22, 191, 139, 229, 226, 26, 39, 53, 128,
+ 229, 200, 38, 141, 97, 57, 178, 144, 237, 58, 191, 47, 204, 75, 174,
+ 189, 97, 57, 178, 190, 79, 89, 142, 236, 223, 187, 49, 58, 245, 246,
+ 121, 228, 126, 123, 89, 142, 236, 247, 98, 44, 71, 118, 177, 167, 248,
+ 157, 115, 111, 243, 145, 7, 222, 138, 164, 57, 178, 223, 251, 168, 24,
+ 204, 7, 243, 18, 175, 94, 163, 117, 116, 85, 88, 102, 223, 122, 240,
+ 163, 52, 206, 75, 244, 190, 1, 65, 207, 43, 167, 112, 223, 92, 222,
+ 52, 216, 27, 115, 102, 226, 28, 25, 171, 191, 244, 135, 190, 137, 91,
+ 220, 56, 175, 156, 194, 229, 175, 146, 185, 243, 202, 105, 198, 213, 197,
+ 32, 95, 154, 191, 2, 26, 101, 42, 50, 182, 24, 87, 23, 227, 207,
+ 201, 192, 113, 147, 177, 164, 109, 54, 174, 46, 6, 249, 58, 157, 35,
+ 211, 100, 132, 108, 54, 174, 46, 6, 245, 110, 100, 253, 37, 234, 216,
+ 200, 250, 75, 212, 167, 145, 245, 151, 33, 155, 141, 173, 191, 68, 156,
+ 16, 204, 36, 172, 7, 59, 72, 209, 195, 12, 171, 191, 12, 129, 190,
+ 233, 27, 221, 248, 230, 242, 38, 238, 91, 197, 127, 49, 254, 161, 27,
+ 141, 171, 139, 65, 190, 244, 155, 203, 64, 163, 76, 197, 99, 111, 48,
+ 174, 46, 38, 132, 147, 129, 227, 38, 99, 177, 110, 48, 174, 46, 6,
+ 249, 58, 125, 115, 89, 147, 225, 187, 193, 184, 186, 24, 212, 187, 145,
+ 245, 151, 168, 99, 35, 235, 47, 173, 27, 140, 173, 191, 244, 221, 96,
+ 108, 253, 37, 226, 132, 126, 79, 198, 18, 238, 157, 190, 73, 15, 51,
+ 172, 254, 210, 23, 250, 38, 172, 213, 199, 12, 182, 35, 118, 144, 176,
+ 142, 241, 247, 95, 107, 92, 156, 65, 190, 68, 134, 47, 208, 40, 83,
+ 153, 197, 38, 25, 23, 103, 124, 57, 25, 56, 110, 50, 22, 75, 146,
+ 113, 113, 6, 249, 242, 152, 241, 213, 100, 36, 193, 111, 99, 84, 156,
+ 65, 189, 27, 89, 127, 137, 58, 54, 178, 254, 210, 146, 100, 108, 253,
+ 37, 234, 206, 200, 250, 75, 196, 9, 253, 182, 127, 227, 71, 158, 9,
+ 235, 245, 48, 195, 213, 95, 102, 132, 123, 103, 124, 245, 200, 83, 183,
+ 254, 18, 218, 209, 26, 252, 144, 55, 158, 244, 23, 135, 190, 70, 197,
+ 25, 228, 75, 109, 173, 199, 35, 79, 148, 169, 216, 156, 64, 198, 127,
+ 141, 51, 200, 151, 214, 69, 3, 95, 50, 150, 196, 54, 217, 203, 248,
+ 175, 113, 6, 249, 242, 152, 65, 153, 202, 254, 101, 227, 236, 101, 252,
+ 215, 56, 131, 122, 55, 178, 254, 210, 55, 11, 191, 156, 214, 95, 162,
+ 62, 141, 172, 191, 68, 221, 25, 89, 127, 137, 56, 161, 223, 147, 233,
+ 11, 118, 192, 249, 51, 215, 152, 97, 245, 151, 9, 141, 160, 175, 172,
+ 143, 25, 108, 71, 99, 64, 35, 246, 219, 39, 74, 217, 219, 129, 59,
+ 113, 102, 210, 194, 8, 59, 141, 1, 156, 140, 4, 120, 167, 4, 77,
+ 142, 111, 255, 236, 101, 184, 19, 103, 22, 116, 98, 53, 43, 200, 151,
+ 142, 3, 104, 50, 150, 196, 126, 217, 203, 112, 39, 206, 216, 46, 60,
+ 11, 166, 227, 144, 157, 49, 131, 50, 149, 117, 153, 64, 134, 59, 113,
+ 166, 249, 160, 110, 20, 51, 168, 247, 236, 238, 238, 66, 157, 50, 222,
+ 174, 255, 189, 51, 247, 233, 159, 61, 63, 212, 223, 127, 229, 135, 250,
+ 204, 142, 31, 234, 234, 191, 242, 11, 16, 240, 67, 189, 184, 203, 143,
+ 126, 79, 166, 47, 195, 76, 68, 47, 160, 57, 127, 230, 26, 51, 172,
+ 254, 50, 0, 250, 38, 133, 233, 99, 6, 219, 209, 239, 176, 244, 97,
+ 252, 45, 97, 57, 139, 51, 163, 63, 107, 79, 231, 102, 200, 151, 198,
+ 50, 160, 81, 166, 146, 113, 235, 157, 179, 56, 147, 158, 60, 138, 206,
+ 205, 2, 56, 25, 56, 110, 50, 150, 208, 222, 57, 139, 51, 127, 124,
+ 249, 47, 197, 12, 242, 117, 250, 158, 140, 38, 35, 163, 87, 206, 226,
+ 76, 207, 251, 61, 216, 247, 100, 194, 178, 183, 33, 212, 233, 127, 181,
+ 73, 212, 113, 118, 252, 80, 127, 255, 149, 95, 168, 128, 31, 234, 234,
+ 191, 242, 67, 221, 101, 199, 15, 245, 242, 95, 49, 163, 224, 132, 172,
+ 107, 35, 193, 14, 250, 234, 96, 166, 14, 171, 191, 204, 232, 249, 200,
+ 51, 49, 90, 31, 51, 216, 142, 230, 155, 98, 24, 127, 107, 207, 156,
+ 197, 25, 167, 188, 89, 12, 147, 225, 15, 116, 134, 198, 59, 32, 58,
+ 103, 113, 198, 41, 111, 198, 201, 192, 113, 147, 177, 164, 69, 229, 44,
+ 206, 56, 229, 205, 162, 157, 49, 227, 175, 201, 8, 137, 202, 89, 156,
+ 113, 250, 110, 89, 79, 206, 134, 12, 88, 207, 160, 142, 141, 92, 207,
+ 160, 62, 141, 92, 207, 132, 68, 57, 191, 95, 78, 215, 51, 136, 19,
+ 154, 55, 27, 253, 200, 51, 162, 151, 30, 102, 216, 121, 204, 16, 232,
+ 155, 62, 86, 31, 51, 216, 142, 230, 155, 198, 49, 254, 161, 99, 141,
+ 91, 207, 32, 95, 154, 55, 3, 26, 101, 42, 184, 30, 99, 220, 122,
+ 38, 132, 147, 129, 227, 38, 99, 177, 142, 49, 110, 61, 131, 124, 157,
+ 242, 102, 154, 12, 223, 49, 198, 173, 103, 80, 239, 70, 174, 103, 80,
+ 199, 70, 174, 103, 172, 99, 140, 93, 207, 248, 142, 49, 118, 61, 131,
+ 56, 33, 152, 9, 25, 14, 118, 16, 169, 135, 25, 246, 29, 102, 95,
+ 232, 155, 48, 82, 31, 51, 216, 142, 174, 53, 70, 49, 254, 254, 35,
+ 141, 139, 51, 200, 151, 174, 53, 128, 70, 153, 74, 190, 105, 132, 113,
+ 113, 198, 151, 147, 129, 227, 38, 99, 177, 140, 48, 46, 206, 32, 95,
+ 167, 188, 153, 38, 35, 125, 184, 113, 113, 6, 245, 110, 228, 254, 12,
+ 234, 216, 200, 253, 25, 203, 136, 156, 199, 25, 167, 185, 227, 240, 156,
+ 199, 25, 126, 110, 134, 56, 161, 152, 233, 2, 118, 48, 90, 15, 51,
+ 236, 59, 204, 233, 195, 30, 121, 250, 119, 211, 199, 12, 182, 163, 49,
+ 96, 24, 227, 239, 24, 106, 92, 156, 9, 225, 100, 36, 194, 59, 165,
+ 107, 114, 146, 186, 26, 23, 103, 144, 47, 157, 255, 1, 77, 198, 98,
+ 233, 106, 92, 156, 241, 239, 230, 140, 25, 148, 169, 232, 186, 139, 113,
+ 113, 6, 245, 110, 228, 254, 12, 234, 216, 200, 253, 25, 75, 215, 156,
+ 199, 25, 39, 204, 116, 201, 121, 156, 113, 194, 76, 23, 134, 25, 107,
+ 42, 216, 193, 240, 108, 48, 51, 188, 251, 208, 97, 89, 238, 145, 77,
+ 239, 12, 237, 59, 185, 129, 153, 206, 28, 102, 58, 51, 254, 1, 29,
+ 179, 183, 131, 216, 214, 211, 236, 7, 10, 52, 212, 48, 227, 229, 58,
+ 7, 208, 39, 15, 187, 227, 149, 147, 145, 14, 239, 148, 174, 201, 241,
+ 237, 32, 144, 177, 176, 76, 234, 189, 220, 165, 131, 85, 204, 184, 150,
+ 113, 115, 116, 5, 54, 255, 235, 196, 141, 3, 104, 50, 150, 140, 246,
+ 217, 203, 24, 155, 249, 40, 245, 232, 192, 175, 181, 187, 151, 93, 203,
+ 8, 253, 242, 61, 154, 255, 11, 233, 228, 140, 25, 148, 169, 16, 91,
+ 179, 151, 209, 236, 239, 174, 230, 253, 251, 8, 102, 92, 203, 168, 126,
+ 92, 173, 149, 201, 208, 244, 94, 69, 105, 169, 222, 39, 130, 122, 164,
+ 57, 0, 141, 14, 89, 56, 94, 98, 207, 93, 159, 37, 57, 181, 182,
+ 128, 92, 108, 72, 43, 237, 188, 119, 11, 153, 180, 247, 121, 220, 81,
+ 158, 148, 80, 73, 184, 118, 121, 154, 127, 144, 188, 251, 205, 4, 122,
+ 79, 102, 171, 17, 234, 221, 142, 185, 50, 227, 228, 182, 59, 215, 136,
+ 107, 26, 114, 77, 145, 55, 92, 76, 165, 119, 93, 18, 58, 226, 198,
+ 119, 220, 243, 236, 231, 107, 25, 154, 93, 240, 58, 192, 223, 153, 232,
+ 128, 208, 168, 3, 246, 60, 123, 29, 172, 152, 18, 78, 239, 138, 34,
+ 237, 81, 7, 30, 47, 11, 218, 244, 116, 176, 237, 230, 28, 122, 79,
+ 215, 160, 204, 70, 41, 68, 7, 27, 118, 120, 166, 232, 233, 224, 250,
+ 248, 127, 147, 137, 14, 8, 141, 58, 96, 207, 197, 58, 64, 187, 229,
+ 117, 128, 118, 72, 116, 64, 232, 54, 160, 3, 246, 60, 155, 111, 214,
+ 128, 14, 46, 151, 252, 202, 78, 116, 64, 218, 231, 7, 29, 244, 45,
+ 34, 62, 187, 255, 4, 116, 112, 114, 219, 80, 122, 127, 212, 161, 98,
+ 37, 109, 68, 7, 79, 23, 39, 235, 234, 96, 226, 252, 69, 41, 68,
+ 7, 132, 70, 29, 176, 231, 98, 29, 32, 174, 120, 29, 32, 78, 136,
+ 14, 8, 141, 118, 192, 158, 103, 111, 7, 7, 183, 198, 208, 187, 117,
+ 72, 251, 124, 160, 131, 252, 167, 197, 231, 200, 208, 14, 254, 188, 19,
+ 67, 239, 154, 249, 94, 59, 191, 137, 58, 168, 245, 72, 220, 23, 117,
+ 208, 129, 158, 83, 155, 73, 105, 212, 65, 7, 157, 243, 107, 36, 6,
+ 160, 223, 167, 49, 96, 19, 248, 181, 46, 194, 24, 224, 116, 47, 163,
+ 9, 250, 90, 109, 24, 3, 170, 166, 133, 133, 85, 148, 55, 148, 158,
+ 187, 181, 195, 166, 222, 22, 169, 145, 135, 83, 12, 192, 118, 196, 175,
+ 89, 237, 220, 250, 60, 37, 123, 191, 182, 96, 84, 160, 189, 66, 169,
+ 239, 133, 49, 224, 92, 196, 253, 20, 34, 3, 249, 82, 223, 137, 50,
+ 82, 181, 57, 77, 114, 246, 50, 194, 62, 44, 159, 218, 98, 252, 246,
+ 134, 162, 24, 208, 170, 194, 192, 64, 58, 14, 78, 6, 142, 155, 140,
+ 197, 127, 75, 246, 50, 28, 233, 143, 82, 27, 253, 220, 77, 24, 3,
+ 222, 126, 146, 143, 198, 0, 228, 235, 180, 223, 72, 244, 181, 57, 123,
+ 25, 219, 7, 132, 154, 167, 108, 21, 199, 0, 180, 67, 98, 247, 168,
+ 119, 222, 238, 81, 143, 132, 31, 161, 209, 238, 217, 115, 147, 233, 59,
+ 83, 77, 211, 50, 211, 135, 166, 85, 240, 71, 108, 232, 52, 216, 253,
+ 149, 219, 201, 245, 137, 221, 147, 246, 232, 255, 50, 206, 188, 175, 235,
+ 255, 254, 90, 97, 165, 216, 239, 208, 243, 39, 138, 253, 191, 167, 172,
+ 178, 233, 217, 253, 208, 111, 237, 244, 14, 55, 66, 163, 221, 179, 231,
+ 98, 236, 163, 93, 240, 58, 192, 223, 153, 232, 128, 208, 168, 3, 246,
+ 28, 117, 240, 225, 59, 58, 64, 236, 183, 237, 227, 77, 239, 83, 39,
+ 237, 81, 7, 223, 166, 87, 12, 212, 211, 193, 235, 179, 151, 146, 137,
+ 14, 110, 207, 108, 67, 99, 64, 201, 215, 147, 117, 253, 223, 45, 207,
+ 89, 212, 255, 17, 26, 117, 192, 158, 139, 117, 128, 118, 203, 235, 0,
+ 237, 144, 232, 128, 208, 24, 3, 216, 115, 212, 193, 71, 160, 131, 154,
+ 160, 131, 154, 78, 49, 224, 196, 208, 214, 52, 6, 144, 246, 24, 3,
+ 62, 220, 152, 161, 27, 3, 186, 79, 235, 69, 237, 96, 124, 61, 31,
+ 106, 7, 11, 60, 23, 234, 234, 224, 74, 116, 36, 213, 1, 161, 81,
+ 7, 236, 185, 78, 12, 216, 236, 172, 3, 230, 175, 173, 102, 66, 163,
+ 29, 240, 126, 252, 59, 83, 99, 208, 65, 99, 208, 65, 99, 39, 59,
+ 8, 220, 205, 98, 0, 105, 143, 49, 160, 205, 121, 253, 24, 144, 114,
+ 143, 197, 128, 181, 15, 88, 12, 88, 233, 70, 12, 232, 193, 197, 128,
+ 30, 92, 12, 232, 225, 110, 12, 216, 196, 98, 128, 101, 61, 248, 181,
+ 84, 189, 24, 192, 242, 77, 38, 232, 107, 221, 168, 191, 14, 192, 118,
+ 212, 119, 254, 197, 248, 251, 110, 116, 119, 29, 224, 122, 61, 136, 115,
+ 62, 234, 59, 255, 226, 124, 39, 202, 216, 164, 237, 109, 111, 112, 119,
+ 29, 224, 90, 6, 206, 169, 232, 56, 56, 25, 56, 110, 50, 150, 128,
+ 13, 238, 174, 3, 92, 203, 192, 57, 11, 29, 199, 198, 44, 49, 64,
+ 147, 145, 182, 222, 221, 117, 64, 54, 121, 134, 187, 49, 116, 237, 140,
+ 122, 231, 239, 244, 97, 115, 103, 171, 153, 208, 235, 44, 54, 139, 104,
+ 78, 237, 180, 223, 189, 193, 153, 31, 155, 135, 90, 205, 132, 94, 15,
+ 252, 68, 243, 83, 167, 253, 238, 44, 252, 216, 156, 206, 106, 38, 52,
+ 242, 19, 205, 245, 156, 206, 23, 175, 119, 230, 199, 230, 71, 86, 51,
+ 161, 145, 159, 104, 222, 196, 175, 157, 17, 39, 4, 51, 105, 127, 131,
+ 29, 108, 210, 195, 12, 203, 55, 165, 173, 123, 228, 105, 89, 171, 63,
+ 111, 194, 118, 196, 14, 44, 235, 24, 255, 244, 36, 119, 231, 77, 174,
+ 237, 0, 99, 36, 145, 97, 225, 100, 164, 193, 59, 165, 105, 114, 66,
+ 147, 220, 157, 55, 185, 150, 129, 49, 136, 142, 99, 45, 55, 14, 160,
+ 201, 88, 146, 118, 187, 59, 111, 114, 45, 3, 125, 60, 29, 199, 90,
+ 103, 204, 160, 76, 101, 254, 183, 219, 221, 121, 147, 107, 25, 61, 56,
+ 204, 160, 222, 121, 27, 98, 115, 13, 171, 153, 208, 104, 67, 162, 57,
+ 136, 211, 126, 119, 22, 126, 44, 110, 91, 205, 132, 70, 126, 162, 120,
+ 238, 148, 191, 218, 237, 204, 143, 197, 64, 171, 153, 208, 200, 79, 20,
+ 27, 157, 242, 87, 89, 248, 245, 224, 48, 211, 131, 195, 76, 15, 55,
+ 49, 131, 56, 161, 107, 141, 237, 96, 7, 235, 245, 48, 195, 234, 78,
+ 44, 208, 55, 109, 167, 126, 156, 193, 118, 212, 158, 119, 49, 254, 33,
+ 59, 141, 139, 51, 200, 151, 218, 51, 208, 40, 83, 201, 3, 239, 48,
+ 46, 206, 88, 56, 25, 56, 110, 50, 150, 136, 29, 198, 197, 25, 228,
+ 203, 99, 198, 66, 244, 181, 195, 184, 56, 131, 122, 39, 54, 148, 102,
+ 218, 186, 213, 85, 156, 49, 221, 139, 116, 59, 206, 160, 142, 121, 126,
+ 174, 226, 12, 242, 115, 55, 206, 68, 100, 225, 231, 42, 206, 32, 63,
+ 119, 227, 140, 41, 11, 63, 87, 113, 6, 249, 185, 27, 103, 16, 39,
+ 236, 14, 35, 176, 131, 191, 245, 48, 195, 234, 78, 76, 208, 215, 154,
+ 230, 198, 250, 124, 59, 55, 167, 217, 198, 248, 39, 29, 54, 46, 206,
+ 32, 95, 106, 107, 40, 99, 187, 230, 159, 15, 27, 23, 103, 76, 156,
+ 12, 28, 55, 25, 75, 250, 33, 227, 226, 12, 242, 117, 154, 155, 105,
+ 50, 66, 15, 25, 23, 103, 80, 239, 188, 13, 185, 138, 51, 104, 67,
+ 238, 198, 25, 75, 22, 126, 174, 226, 12, 242, 115, 55, 206, 160, 62,
+ 121, 126, 174, 226, 12, 242, 115, 55, 206, 132, 102, 225, 231, 42, 206,
+ 32, 63, 119, 227, 12, 226, 132, 221, 97, 4, 118, 176, 93, 15, 51,
+ 159, 114, 119, 24, 61, 242, 116, 236, 119, 227, 12, 253, 65, 102, 7,
+ 142, 3, 140, 127, 196, 126, 227, 226, 12, 242, 101, 119, 24, 61, 242,
+ 68, 153, 74, 163, 253, 198, 197, 153, 80, 78, 6, 142, 155, 140, 37,
+ 97, 159, 113, 113, 6, 249, 58, 223, 97, 164, 229, 205, 246, 25, 23,
+ 103, 80, 239, 57, 141, 51, 38, 167, 59, 140, 114, 30, 103, 76, 78,
+ 119, 24, 229, 60, 206, 152, 156, 238, 48, 202, 121, 156, 49, 57, 221,
+ 97, 196, 48, 19, 122, 14, 236, 224, 160, 30, 102, 62, 227, 238, 48,
+ 122, 228, 153, 120, 65, 63, 206, 96, 59, 186, 183, 125, 145, 219, 11,
+ 188, 96, 92, 156, 65, 190, 116, 111, 27, 104, 148, 169, 172, 7, 206,
+ 27, 23, 103, 252, 57, 25, 56, 110, 50, 150, 144, 243, 198, 197, 25,
+ 228, 235, 116, 182, 81, 147, 225, 56, 103, 92, 156, 65, 189, 231, 52,
+ 206, 56, 157, 69, 60, 159, 243, 56, 227, 116, 22, 241, 124, 206, 227,
+ 12, 207, 15, 117, 151, 211, 56, 195, 99, 6, 113, 66, 239, 99, 57,
+ 5, 118, 176, 87, 15, 51, 172, 238, 196, 113, 22, 252, 249, 25, 253,
+ 56, 131, 237, 104, 12, 56, 203, 248, 103, 156, 206, 89, 156, 225, 247,
+ 207, 67, 57, 25, 14, 120, 39, 135, 38, 199, 122, 58, 103, 113, 134,
+ 223, 63, 71, 190, 116, 28, 64, 147, 177, 248, 158, 206, 89, 156, 225,
+ 247, 207, 67, 207, 56, 99, 6, 101, 42, 249, 191, 83, 57, 139, 51,
+ 100, 255, 60, 72, 211, 59, 189, 211, 167, 155, 119, 218, 232, 3, 207,
+ 222, 217, 63, 79, 74, 59, 108, 158, 248, 251, 232, 192, 236, 246, 12,
+ 157, 106, 120, 57, 126, 37, 186, 122, 167, 205, 47, 253, 107, 80, 214,
+ 189, 104, 199, 246, 195, 230, 209, 241, 110, 222, 97, 196, 241, 75, 107,
+ 225, 157, 86, 108, 72, 155, 134, 89, 247, 117, 67, 79, 30, 54, 23,
+ 110, 255, 149, 221, 29, 126, 168, 59, 194, 47, 52, 212, 59, 13, 117,
+ 149, 117, 143, 212, 10, 227, 109, 50, 54, 198, 189, 59, 140, 78, 113,
+ 235, 153, 99, 96, 7, 231, 244, 48, 195, 234, 78, 18, 255, 1, 127,
+ 126, 82, 63, 206, 96, 59, 26, 3, 254, 225, 214, 51, 39, 114, 22,
+ 103, 248, 253, 70, 127, 78, 70, 34, 188, 83, 162, 38, 199, 114, 34,
+ 103, 113, 134, 223, 111, 68, 190, 116, 28, 64, 147, 177, 164, 31, 207,
+ 89, 156, 225, 247, 27, 253, 79, 102, 57, 167, 117, 82, 91, 207, 28,
+ 207, 89, 156, 33, 251, 141, 65, 154, 222, 137, 13, 205, 7, 204, 92,
+ 26, 243, 216, 150, 117, 191, 49, 13, 108, 104, 229, 184, 207, 178, 221,
+ 111, 116, 90, 207, 112, 252, 38, 3, 191, 6, 107, 199, 217, 222, 217,
+ 187, 219, 118, 216, 28, 212, 229, 97, 182, 123, 119, 78, 235, 153, 227,
+ 140, 223, 104, 192, 76, 205, 125, 223, 52, 204, 186, 15, 150, 4, 152,
+ 233, 180, 169, 117, 182, 251, 96, 78, 235, 153, 227, 206, 152, 65, 93,
+ 101, 221, 83, 66, 204, 252, 58, 62, 251, 61, 37, 167, 245, 204, 49,
+ 110, 61, 115, 9, 236, 224, 148, 14, 102, 184, 123, 191, 66, 161, 175,
+ 227, 136, 27, 235, 153, 99, 92, 12, 56, 202, 213, 55, 222, 113, 55,
+ 206, 20, 116, 105, 7, 43, 228, 125, 244, 155, 198, 200, 151, 198, 0,
+ 160, 81, 166, 50, 183, 185, 229, 110, 156, 113, 45, 35, 180, 79, 50,
+ 91, 207, 112, 50, 112, 220, 100, 44, 137, 215, 220, 141, 51, 217, 200,
+ 184, 91, 143, 197, 178, 35, 89, 214, 51, 154, 12, 255, 203, 238, 198,
+ 25, 215, 50, 182, 189, 82, 49, 243, 121, 46, 85, 239, 85, 148, 150,
+ 38, 83, 116, 141, 15, 211, 80, 143, 132, 31, 161, 27, 36, 197, 91,
+ 216, 115, 215, 223, 33, 29, 220, 58, 211, 210, 191, 95, 121, 205, 158,
+ 3, 164, 197, 129, 181, 20, 250, 127, 167, 186, 75, 248, 219, 137, 206,
+ 181, 188, 231, 55, 75, 98, 241, 109, 57, 61, 19, 150, 63, 243, 15,
+ 73, 20, 223, 176, 111, 102, 174, 245, 210, 189, 184, 181, 244, 190, 157,
+ 193, 203, 212, 187, 172, 60, 50, 109, 210, 143, 77, 19, 132, 231, 170,
+ 94, 229, 218, 33, 133, 140, 220, 77, 191, 225, 103, 93, 175, 221, 71,
+ 149, 121, 64, 106, 241, 188, 144, 240, 60, 210, 203, 92, 199, 164, 246,
+ 123, 63, 208, 218, 156, 146, 138, 127, 25, 164, 210, 209, 103, 164, 65,
+ 62, 77, 132, 125, 95, 199, 158, 151, 102, 31, 108, 169, 181, 113, 72,
+ 158, 141, 212, 24, 137, 223, 151, 31, 178, 249, 27, 97, 223, 92, 113,
+ 215, 164, 239, 31, 182, 213, 218, 220, 148, 202, 111, 234, 162, 208, 190,
+ 209, 183, 165, 135, 227, 250, 8, 251, 150, 143, 187, 43, 33, 150, 180,
+ 153, 157, 100, 181, 68, 42, 244, 252, 232, 135, 82, 159, 51, 221, 133,
+ 125, 15, 199, 62, 145, 26, 77, 190, 64, 191, 233, 233, 223, 82, 189,
+ 155, 106, 75, 212, 75, 233, 235, 53, 167, 55, 139, 250, 218, 98, 95,
+ 75, 79, 99, 190, 161, 223, 7, 222, 95, 98, 170, 66, 191, 10, 246,
+ 144, 207, 223, 93, 46, 190, 143, 42, 205, 83, 30, 177, 176, 15, 253,
+ 14, 223, 155, 15, 219, 169, 116, 116, 30, 121, 112, 171, 143, 116, 238,
+ 159, 201, 39, 159, 121, 213, 136, 126, 227, 247, 217, 167, 13, 232, 221,
+ 53, 126, 67, 3, 116, 239, 174, 97, 103, 19, 253, 40, 141, 223, 191,
+ 210, 59, 179, 72, 176, 133, 254, 134, 96, 11, 239, 193, 66, 255, 65,
+ 231, 72, 26, 45, 1, 182, 216, 115, 215, 216, 218, 6, 216, 202, 95,
+ 109, 90, 10, 193, 86, 82, 155, 207, 21, 58, 24, 176, 245, 217, 202,
+ 199, 194, 187, 157, 26, 2, 182, 216, 92, 111, 57, 61, 107, 88, 11,
+ 176, 37, 154, 235, 97, 223, 2, 94, 235, 165, 60, 39, 124, 236, 4,
+ 91, 219, 171, 202, 10, 157, 15, 176, 21, 62, 102, 140, 208, 94, 254,
+ 5, 108, 45, 155, 246, 43, 189, 219, 110, 198, 89, 155, 66, 63, 126,
+ 117, 64, 58, 248, 193, 73, 97, 95, 47, 175, 99, 210, 218, 186, 119,
+ 40, 182, 22, 188, 246, 80, 206, 45, 215, 3, 108, 229, 205, 240, 22,
+ 126, 199, 208, 39, 254, 188, 132, 190, 156, 96, 171, 240, 60, 31, 133,
+ 246, 138, 187, 44, 229, 63, 147, 33, 148, 219, 127, 252, 53, 233, 88,
+ 68, 56, 197, 214, 149, 184, 210, 138, 126, 126, 6, 108, 85, 92, 90,
+ 65, 232, 195, 74, 143, 187, 43, 69, 22, 205, 71, 191, 113, 217, 223,
+ 175, 136, 66, 127, 111, 125, 40, 221, 133, 184, 34, 234, 123, 9, 176,
+ 213, 120, 246, 210, 134, 4, 91, 123, 199, 215, 87, 104, 63, 192, 214,
+ 197, 233, 213, 133, 182, 246, 32, 230, 181, 36, 207, 43, 64, 198, 37,
+ 247, 75, 104, 163, 208, 179, 1, 91, 185, 23, 77, 21, 142, 247, 14,
+ 96, 171, 89, 46, 114, 119, 161, 151, 252, 123, 165, 177, 10, 93, 8,
+ 176, 53, 178, 107, 127, 29, 31, 150, 79, 126, 83, 169, 134, 157, 96,
+ 107, 206, 7, 185, 21, 58, 51, 170, 160, 92, 184, 231, 118, 155, 30,
+ 182, 216, 153, 87, 63, 74, 227, 247, 179, 245, 206, 194, 210, 184, 117,
+ 141, 97, 107, 22, 98, 11, 226, 38, 197, 150, 70, 43, 216, 162, 207,
+ 9, 182, 222, 189, 175, 242, 104, 183, 149, 244, 251, 217, 197, 103, 77,
+ 87, 232, 98, 167, 187, 75, 9, 227, 186, 8, 223, 165, 111, 177, 89,
+ 18, 91, 247, 44, 167, 103, 88, 195, 94, 255, 33, 137, 214, 61, 216,
+ 119, 50, 96, 235, 11, 223, 227, 20, 91, 255, 171, 80, 68, 177, 83,
+ 11, 96, 107, 154, 165, 129, 208, 198, 127, 6, 108, 181, 92, 62, 36,
+ 149, 96, 171, 121, 216, 116, 133, 62, 6, 216, 250, 242, 233, 18, 97,
+ 223, 23, 128, 173, 118, 215, 215, 166, 18, 108, 149, 239, 189, 71, 161,
+ 243, 198, 156, 145, 186, 175, 58, 38, 236, 107, 25, 127, 94, 194, 57,
+ 12, 193, 214, 221, 63, 174, 42, 116, 163, 217, 151, 37, 251, 169, 227,
+ 194, 190, 227, 18, 174, 73, 109, 27, 206, 77, 37, 216, 178, 125, 92,
+ 95, 161, 235, 143, 191, 45, 13, 238, 61, 93, 168, 171, 69, 157, 239,
+ 74, 127, 125, 82, 142, 98, 171, 118, 68, 3, 133, 94, 51, 225, 161,
+ 116, 4, 230, 83, 162, 190, 243, 162, 158, 72, 201, 103, 250, 80, 108,
+ 45, 238, 222, 89, 241, 157, 211, 70, 191, 148, 74, 255, 28, 35, 148,
+ 251, 89, 212, 107, 169, 72, 255, 71, 20, 91, 17, 113, 249, 149, 119,
+ 158, 0, 216, 42, 91, 173, 108, 170, 30, 182, 70, 143, 32, 223, 16,
+ 246, 146, 171, 52, 120, 165, 240, 241, 2, 108, 205, 61, 243, 143, 80,
+ 238, 77, 192, 86, 205, 87, 75, 41, 182, 34, 214, 170, 247, 136, 222,
+ 5, 108, 125, 123, 172, 157, 176, 111, 38, 96, 139, 157, 165, 246, 163,
+ 116, 50, 96, 75, 239, 140, 53, 141, 91, 151, 25, 182, 240, 219, 244,
+ 56, 95, 36, 216, 34, 52, 126, 3, 150, 61, 119, 253, 13, 216, 52,
+ 192, 86, 194, 124, 118, 79, 210, 230, 100, 149, 174, 8, 113, 203, 113,
+ 78, 124, 214, 249, 113, 209, 89, 18, 203, 1, 44, 167, 103, 163, 243,
+ 66, 220, 18, 229, 0, 148, 24, 0, 216, 170, 190, 147, 221, 117, 20,
+ 81, 68, 253, 230, 103, 41, 192, 214, 31, 161, 227, 132, 125, 11, 121,
+ 237, 144, 198, 121, 140, 166, 223, 98, 45, 127, 95, 253, 38, 106, 69,
+ 152, 19, 254, 118, 78, 124, 79, 82, 115, 192, 86, 157, 242, 225, 244,
+ 123, 170, 69, 188, 251, 41, 180, 4, 113, 235, 199, 177, 97, 194, 190,
+ 29, 226, 206, 75, 56, 119, 39, 216, 218, 237, 173, 126, 55, 192, 110,
+ 189, 44, 181, 110, 217, 91, 216, 183, 119, 204, 53, 105, 40, 189, 75,
+ 233, 166, 180, 161, 135, 58, 198, 47, 163, 110, 75, 87, 3, 196, 186,
+ 218, 20, 123, 87, 42, 91, 123, 52, 253, 158, 234, 147, 153, 42, 221,
+ 8, 230, 132, 7, 238, 136, 191, 211, 187, 21, 226, 86, 169, 147, 209,
+ 244, 123, 170, 159, 255, 21, 163, 125, 199, 245, 165, 244, 113, 115, 241,
+ 29, 75, 15, 97, 78, 120, 195, 70, 191, 215, 42, 95, 14, 82, 105,
+ 188, 191, 204, 97, 139, 212, 189, 115, 104, 83, 72, 20, 253, 158, 106,
+ 112, 66, 148, 118, 215, 81, 30, 185, 69, 161, 104, 179, 222, 156, 240,
+ 219, 127, 163, 233, 55, 81, 189, 191, 32, 247, 66, 21, 148, 55, 254,
+ 30, 99, 214, 139, 91, 236, 140, 190, 31, 165, 113, 78, 168, 119, 118,
+ 159, 238, 127, 92, 226, 114, 185, 177, 176, 110, 60, 166, 183, 198, 102,
+ 231, 224, 67, 97, 61, 152, 56, 75, 63, 47, 21, 202, 173, 27, 29,
+ 233, 92, 205, 237, 116, 119, 243, 82, 174, 215, 141, 63, 70, 236, 164,
+ 247, 94, 35, 95, 186, 198, 6, 26, 101, 42, 235, 223, 201, 238, 230,
+ 165, 92, 203, 168, 210, 38, 141, 202, 8, 229, 100, 224, 184, 201, 88,
+ 252, 39, 184, 155, 151, 114, 45, 35, 207, 125, 137, 237, 227, 204, 202,
+ 178, 198, 214, 100, 36, 198, 186, 155, 151, 114, 45, 163, 49, 183, 198,
+ 70, 189, 19, 127, 26, 9, 254, 20, 245, 72, 248, 17, 26, 215, 216,
+ 236, 57, 241, 167, 31, 154, 2, 185, 51, 224, 3, 193, 159, 14, 247,
+ 47, 75, 191, 207, 255, 127, 228, 125, 119, 116, 20, 85, 244, 255, 38,
+ 244, 30, 32, 116, 132, 208, 73, 1, 150, 42, 66, 96, 119, 134, 162,
+ 244, 80, 20, 172, 132, 14, 210, 130, 244, 146, 176, 9, 32, 82, 132,
+ 40, 8, 34, 136, 1, 21, 34, 2, 198, 0, 138, 144, 132, 13, 77,
+ 164, 70, 138, 70, 138, 44, 189, 72, 9, 33, 129, 16, 8, 252, 238,
+ 157, 153, 87, 38, 108, 102, 246, 251, 203, 251, 227, 123, 206, 55, 231,
+ 236, 225, 158, 225, 221, 123, 231, 221, 185, 159, 119, 95, 187, 239, 149,
+ 232, 30, 164, 208, 45, 161, 61, 197, 239, 71, 120, 251, 90, 2, 45,
+ 35, 224, 55, 147, 219, 59, 93, 10, 198, 1, 108, 62, 44, 150, 238,
+ 185, 47, 9, 237, 169, 209, 124, 24, 242, 90, 160, 61, 13, 47, 122,
+ 172, 45, 105, 79, 227, 214, 191, 163, 222, 179, 2, 237, 105, 74, 232,
+ 70, 218, 63, 141, 3, 158, 237, 240, 219, 105, 105, 196, 48, 3, 125,
+ 149, 132, 116, 114, 39, 205, 33, 169, 126, 72, 101, 37, 22, 23, 132,
+ 246, 52, 103, 195, 171, 180, 79, 157, 8, 60, 201, 240, 59, 192, 241,
+ 230, 192, 24, 123, 114, 249, 129, 237, 72, 123, 122, 227, 89, 68, 59,
+ 50, 198, 62, 60, 109, 62, 229, 61, 12, 60, 199, 45, 141, 45, 41,
+ 240, 227, 239, 169, 70, 127, 38, 237, 169, 245, 194, 114, 133, 46, 14,
+ 99, 108, 91, 204, 114, 202, 123, 18, 120, 78, 195, 239, 47, 142, 55,
+ 59, 242, 154, 180, 225, 206, 92, 122, 31, 100, 161, 59, 170, 94, 188,
+ 55, 35, 229, 249, 68, 202, 155, 10, 60, 103, 225, 119, 158, 123, 231,
+ 202, 48, 198, 190, 208, 115, 70, 59, 210, 158, 222, 122, 109, 176, 66,
+ 55, 135, 246, 180, 70, 237, 174, 148, 247, 34, 240, 93, 2, 190, 43,
+ 28, 47, 158, 79, 237, 10, 46, 65, 251, 42, 133, 171, 169, 247, 231,
+ 166, 65, 123, 122, 110, 214, 8, 106, 231, 107, 192, 115, 3, 126, 183,
+ 184, 111, 116, 24, 218, 211, 137, 67, 206, 145, 113, 184, 92, 51, 76,
+ 205, 243, 194, 246, 180, 79, 246, 30, 250, 125, 239, 0, 207, 61, 248,
+ 165, 113, 188, 79, 161, 61, 205, 217, 96, 163, 119, 240, 84, 236, 59,
+ 175, 173, 218, 38, 22, 150, 223, 232, 157, 66, 231, 95, 210, 129, 39,
+ 3, 126, 89, 28, 47, 182, 167, 117, 35, 106, 183, 33, 237, 233, 142,
+ 35, 167, 119, 145, 246, 212, 119, 116, 56, 213, 155, 131, 60, 94, 65,
+ 150, 66, 94, 65, 186, 246, 148, 229, 126, 248, 82, 26, 219, 83, 62,
+ 39, 164, 56, 240, 148, 134, 95, 57, 142, 151, 142, 3, 62, 209, 143,
+ 177, 177, 253, 32, 216, 34, 52, 142, 3, 216, 115, 247, 216, 194, 49,
+ 246, 249, 83, 75, 232, 93, 211, 227, 78, 118, 84, 232, 70, 128, 173,
+ 202, 217, 236, 158, 169, 190, 192, 51, 2, 126, 51, 57, 222, 50, 128,
+ 45, 54, 55, 28, 75, 115, 57, 42, 0, 182, 140, 230, 134, 149, 111,
+ 94, 96, 155, 244, 236, 55, 114, 127, 242, 78, 233, 159, 71, 218, 253,
+ 80, 128, 173, 147, 171, 202, 183, 99, 216, 106, 4, 216, 106, 164, 195,
+ 86, 58, 96, 107, 244, 170, 246, 237, 8, 182, 250, 78, 121, 179, 157,
+ 186, 159, 255, 168, 84, 180, 239, 24, 67, 108, 213, 130, 190, 74, 175,
+ 117, 163, 40, 182, 90, 215, 93, 168, 249, 233, 89, 169, 214, 137, 229,
+ 134, 216, 122, 7, 250, 42, 216, 142, 19, 108, 189, 253, 243, 143, 10,
+ 61, 22, 250, 42, 247, 247, 27, 99, 235, 222, 156, 107, 210, 235, 147,
+ 239, 208, 251, 173, 146, 34, 235, 42, 118, 251, 15, 176, 213, 177, 89,
+ 151, 68, 134, 173, 70, 128, 173, 32, 192, 22, 107, 195, 134, 133, 223,
+ 149, 18, 55, 91, 146, 8, 182, 182, 62, 45, 163, 208, 27, 194, 211,
+ 165, 17, 65, 53, 147, 24, 182, 252, 1, 91, 254, 128, 173, 134, 28,
+ 62, 50, 165, 183, 26, 164, 39, 18, 108, 109, 219, 118, 82, 161, 255,
+ 4, 108, 21, 237, 180, 45, 145, 97, 203, 31, 176, 21, 0, 216, 10,
+ 160, 188, 223, 1, 182, 14, 223, 161, 99, 20, 185, 74, 85, 117, 238,
+ 227, 54, 96, 235, 139, 65, 3, 18, 25, 182, 2, 0, 91, 129, 128,
+ 173, 64, 221, 157, 52, 47, 122, 189, 71, 199, 216, 183, 19, 187, 39,
+ 170, 237, 80, 97, 121, 196, 170, 70, 137, 12, 91, 129, 128, 173, 64,
+ 192, 86, 32, 215, 14, 21, 147, 187, 119, 56, 79, 239, 149, 153, 61,
+ 70, 189, 123, 254, 41, 140, 3, 238, 55, 98, 121, 79, 57, 200, 227,
+ 6, 91, 44, 167, 200, 151, 210, 56, 198, 230, 115, 141, 140, 176, 133,
+ 113, 150, 96, 107, 9, 96, 11, 227, 38, 193, 22, 161, 17, 91, 236,
+ 57, 98, 203, 255, 37, 108, 237, 7, 108, 149, 61, 203, 198, 216, 107,
+ 55, 168, 119, 84, 85, 133, 49, 118, 217, 107, 253, 18, 140, 176, 53,
+ 1, 198, 216, 108, 157, 36, 150, 230, 8, 141, 134, 49, 182, 209, 58,
+ 9, 242, 206, 131, 184, 181, 114, 255, 41, 58, 198, 62, 89, 83, 29,
+ 99, 183, 1, 108, 189, 63, 132, 141, 177, 227, 224, 187, 109, 135, 239,
+ 190, 147, 243, 151, 207, 1, 91, 247, 158, 179, 49, 246, 128, 46, 234,
+ 24, 251, 56, 140, 177, 143, 71, 179, 49, 118, 162, 165, 62, 96, 171,
+ 62, 96, 171, 30, 229, 173, 94, 232, 148, 212, 169, 111, 28, 29, 99,
+ 55, 206, 58, 168, 208, 1, 48, 198, 158, 210, 231, 100, 18, 195, 86,
+ 93, 192, 86, 29, 192, 86, 109, 202, 59, 26, 198, 216, 216, 135, 33,
+ 216, 10, 125, 113, 69, 161, 7, 125, 126, 89, 90, 187, 134, 141, 207,
+ 79, 90, 106, 1, 182, 106, 1, 182, 24, 239, 8, 24, 99, 63, 29,
+ 20, 77, 199, 216, 203, 6, 55, 81, 232, 213, 115, 110, 75, 155, 167,
+ 142, 226, 176, 85, 15, 176, 213, 80, 135, 173, 75, 239, 222, 149, 238,
+ 183, 12, 162, 99, 108, 215, 244, 206, 10, 29, 53, 63, 93, 146, 161,
+ 63, 197, 176, 101, 5, 108, 53, 5, 108, 53, 165, 188, 205, 97, 140,
+ 109, 153, 57, 129, 198, 45, 223, 231, 95, 41, 109, 247, 197, 169, 217,
+ 210, 168, 107, 11, 18, 245, 113, 43, 72, 135, 173, 117, 179, 114, 164,
+ 230, 109, 188, 73, 189, 228, 173, 77, 43, 40, 244, 100, 192, 214, 168,
+ 172, 6, 73, 12, 91, 254, 128, 45, 127, 192, 86, 67, 221, 24, 123,
+ 86, 168, 15, 29, 99, 187, 182, 169, 227, 109, 196, 86, 221, 95, 175,
+ 115, 216, 242, 7, 108, 249, 3, 182, 252, 185, 57, 183, 98, 114, 213,
+ 233, 63, 210, 49, 118, 194, 13, 117, 174, 236, 58, 96, 107, 85, 60,
+ 27, 99, 231, 224, 187, 122, 5, 0, 182, 152, 173, 158, 2, 182, 88,
+ 174, 154, 47, 165, 119, 3, 182, 248, 28, 182, 226, 192, 83, 26, 126,
+ 229, 56, 94, 26, 183, 34, 245, 99, 236, 142, 220, 24, 187, 35, 55,
+ 198, 238, 248, 210, 24, 187, 35, 96, 171, 163, 110, 140, 253, 211, 106,
+ 54, 198, 238, 145, 192, 198, 216, 255, 113, 99, 236, 190, 192, 51, 2,
+ 126, 51, 57, 94, 28, 99, 179, 53, 195, 88, 154, 123, 134, 99, 108,
+ 163, 53, 67, 228, 45, 6, 216, 90, 149, 202, 198, 216, 139, 36, 117,
+ 12, 86, 9, 176, 53, 113, 19, 27, 99, 199, 1, 207, 118, 248, 237,
+ 180, 116, 96, 119, 87, 195, 24, 251, 240, 52, 54, 198, 14, 140, 157,
+ 172, 208, 53, 33, 110, 77, 250, 251, 35, 27, 195, 86, 7, 192, 86,
+ 7, 192, 86, 7, 238, 46, 246, 83, 82, 191, 109, 227, 233, 24, 123,
+ 197, 118, 245, 126, 151, 142, 216, 39, 108, 49, 210, 198, 176, 37, 3,
+ 182, 100, 192, 150, 76, 121, 37, 136, 91, 216, 119, 39, 216, 106, 48,
+ 81, 189, 211, 101, 17, 196, 173, 135, 225, 108, 124, 126, 210, 34, 1,
+ 182, 36, 192, 150, 68, 121, 163, 97, 140, 61, 35, 112, 26, 29, 99,
+ 191, 177, 77, 173, 227, 24, 24, 99, 159, 105, 197, 108, 149, 10, 239,
+ 122, 22, 126, 231, 57, 91, 197, 195, 24, 123, 99, 97, 54, 198, 126,
+ 175, 190, 74, 183, 130, 62, 161, 79, 103, 54, 198, 190, 8, 124, 151,
+ 224, 119, 133, 171, 239, 17, 136, 91, 103, 226, 216, 157, 37, 227, 180,
+ 251, 135, 159, 66, 220, 122, 56, 158, 233, 189, 6, 250, 110, 192, 239,
+ 22, 167, 247, 17, 196, 173, 126, 85, 217, 24, 123, 255, 31, 179, 232,
+ 157, 37, 173, 166, 179, 49, 246, 29, 224, 185, 7, 191, 52, 142, 23,
+ 199, 216, 127, 212, 97, 99, 236, 94, 19, 217, 24, 251, 157, 114, 108,
+ 140, 157, 14, 60, 25, 240, 203, 226, 120, 177, 79, 88, 33, 135, 141,
+ 177, 223, 255, 128, 141, 177, 191, 223, 195, 222, 57, 7, 121, 188, 58,
+ 2, 182, 58, 234, 226, 22, 203, 129, 244, 165, 52, 246, 9, 249, 220,
+ 200, 226, 192, 83, 26, 126, 229, 56, 94, 186, 247, 35, 146, 141, 177,
+ 45, 107, 96, 204, 124, 201, 108, 140, 205, 242, 63, 98, 28, 15, 189,
+ 237, 107, 205, 215, 177, 177, 28, 205, 205, 248, 134, 203, 153, 250, 90,
+ 220, 190, 92, 148, 75, 115, 51, 224, 157, 80, 167, 50, 70, 253, 90,
+ 220, 190, 92, 148, 75, 235, 1, 52, 169, 75, 218, 26, 113, 251, 114,
+ 237, 107, 115, 229, 76, 173, 213, 246, 125, 173, 17, 183, 47, 23, 237,
+ 46, 50, 255, 35, 244, 107, 177, 249, 31, 104, 79, 145, 249, 31, 142,
+ 53, 98, 243, 63, 16, 39, 52, 207, 112, 229, 67, 111, 191, 72, 51,
+ 204, 176, 252, 15, 199, 106, 40, 251, 149, 249, 188, 20, 150, 163, 126,
+ 176, 154, 201, 143, 94, 37, 110, 95, 174, 133, 211, 225, 128, 119, 114,
+ 104, 122, 252, 86, 137, 219, 151, 139, 114, 105, 61, 128, 38, 117, 137,
+ 251, 82, 220, 190, 92, 203, 87, 122, 204, 160, 78, 165, 79, 240, 165,
+ 184, 125, 185, 104, 119, 145, 249, 31, 126, 171, 196, 230, 127, 160, 61,
+ 69, 230, 127, 216, 191, 20, 155, 255, 129, 56, 161, 121, 134, 203, 224,
+ 187, 172, 49, 195, 12, 203, 255, 176, 3, 175, 243, 11, 15, 242, 12,
+ 87, 114, 49, 96, 5, 151, 103, 248, 133, 192, 60, 195, 21, 92, 12,
+ 0, 26, 117, 42, 61, 164, 229, 2, 243, 12, 57, 29, 88, 111, 82,
+ 151, 176, 229, 2, 243, 12, 191, 200, 149, 103, 72, 236, 181, 92, 96,
+ 158, 225, 23, 98, 243, 63, 208, 198, 34, 243, 63, 194, 150, 139, 205,
+ 255, 176, 44, 23, 155, 255, 129, 56, 161, 231, 39, 110, 5, 63, 88,
+ 105, 134, 25, 150, 255, 97, 1, 94, 199, 103, 30, 228, 25, 46, 227,
+ 98, 192, 231, 220, 25, 16, 159, 9, 204, 51, 252, 156, 243, 53, 212,
+ 177, 76, 139, 1, 63, 9, 204, 51, 228, 116, 96, 189, 73, 93, 236,
+ 63, 9, 204, 51, 252, 44, 87, 158, 161, 166, 35, 101, 171, 184, 56,
+ 131, 118, 23, 153, 255, 129, 54, 22, 153, 255, 97, 255, 73, 108, 254,
+ 7, 218, 78, 100, 254, 7, 226, 132, 222, 213, 179, 9, 252, 96, 153,
+ 25, 102, 88, 254, 71, 202, 150, 135, 222, 33, 155, 61, 56, 63, 113,
+ 11, 119, 238, 224, 22, 238, 204, 209, 31, 197, 197, 153, 16, 78, 71,
+ 10, 188, 83, 138, 166, 39, 236, 71, 113, 113, 6, 229, 210, 122, 0,
+ 77, 235, 242, 163, 184, 56, 19, 178, 57, 215, 249, 137, 155, 181, 92,
+ 198, 77, 226, 226, 12, 218, 93, 228, 120, 38, 236, 71, 177, 227, 25,
+ 203, 143, 98, 199, 51, 104, 59, 145, 227, 25, 196, 9, 189, 67, 225,
+ 123, 240, 131, 173, 102, 152, 97, 249, 31, 209, 63, 0, 111, 172, 121,
+ 156, 193, 114, 244, 220, 233, 31, 184, 189, 236, 27, 197, 197, 25, 31,
+ 78, 71, 52, 188, 83, 180, 166, 199, 186, 81, 92, 156, 65, 185, 180,
+ 30, 64, 147, 186, 56, 55, 136, 139, 51, 62, 177, 185, 238, 234, 137,
+ 213, 114, 25, 55, 136, 139, 51, 104, 119, 145, 227, 25, 235, 70, 177,
+ 227, 25, 180, 167, 200, 241, 76, 200, 6, 177, 227, 25, 196, 9, 189,
+ 71, 241, 5, 208, 155, 76, 48, 195, 221, 59, 18, 2, 188, 41, 223,
+ 122, 112, 135, 194, 247, 92, 12, 248, 142, 59, 163, 241, 91, 113, 113,
+ 6, 229, 210, 24, 0, 52, 234, 84, 230, 180, 214, 139, 139, 51, 33,
+ 156, 14, 172, 55, 169, 139, 99, 189, 184, 56, 131, 114, 117, 119, 40,
+ 104, 58, 226, 94, 136, 139, 51, 104, 119, 145, 227, 25, 180, 177, 200,
+ 241, 140, 99, 189, 216, 241, 12, 218, 78, 228, 120, 70, 193, 137, 38,
+ 47, 45, 27, 252, 224, 123, 51, 204, 176, 253, 92, 113, 207, 31, 122,
+ 91, 115, 204, 227, 12, 150, 163, 119, 79, 61, 103, 242, 157, 207, 196,
+ 197, 25, 43, 167, 35, 14, 222, 41, 78, 211, 19, 242, 76, 92, 156,
+ 65, 185, 180, 30, 64, 147, 186, 184, 158, 138, 139, 51, 214, 28, 61,
+ 102, 80, 167, 210, 199, 124, 42, 46, 206, 160, 221, 69, 142, 103, 66,
+ 158, 137, 29, 207, 160, 61, 69, 142, 103, 194, 158, 138, 29, 207, 32,
+ 78, 232, 61, 138, 143, 192, 15, 94, 152, 97, 134, 157, 3, 25, 6,
+ 188, 105, 89, 230, 113, 6, 203, 209, 59, 59, 159, 112, 247, 91, 101,
+ 137, 139, 51, 40, 151, 232, 8, 3, 26, 117, 42, 243, 12, 89, 226,
+ 226, 76, 24, 167, 3, 235, 77, 234, 18, 243, 88, 92, 156, 65, 185,
+ 60, 102, 194, 52, 29, 214, 199, 226, 226, 12, 218, 93, 228, 120, 198,
+ 39, 75, 236, 120, 6, 237, 41, 114, 60, 99, 125, 44, 118, 60, 131,
+ 56, 161, 247, 40, 166, 131, 31, 100, 155, 97, 134, 157, 3, 105, 5,
+ 222, 184, 12, 243, 56, 131, 229, 104, 12, 200, 228, 238, 81, 204, 16,
+ 23, 103, 80, 46, 141, 1, 64, 163, 78, 101, 12, 253, 80, 92, 156,
+ 177, 114, 58, 176, 222, 164, 46, 161, 15, 197, 197, 25, 148, 171, 187,
+ 71, 81, 211, 145, 150, 46, 46, 206, 160, 221, 69, 142, 103, 208, 198,
+ 34, 199, 51, 161, 15, 197, 142, 103, 208, 118, 34, 199, 51, 136, 19,
+ 122, 222, 112, 161, 12, 239, 184, 71, 110, 48, 19, 54, 108, 204, 148,
+ 81, 234, 121, 243, 22, 238, 123, 164, 61, 120, 232, 237, 87, 58, 3,
+ 48, 83, 88, 26, 62, 188, 134, 188, 102, 73, 216, 158, 10, 217, 85,
+ 236, 47, 221, 163, 248, 128, 139, 1, 15, 184, 243, 185, 74, 101, 228,
+ 233, 7, 72, 29, 59, 122, 84, 195, 140, 183, 197, 219, 226, 254, 143,
+ 198, 0, 94, 71, 127, 192, 190, 166, 199, 89, 210, 19, 29, 213, 60,
+ 211, 209, 159, 219, 107, 95, 38, 195, 155, 212, 197, 199, 35, 29, 213,
+ 61, 210, 129, 114, 233, 57, 19, 168, 67, 187, 211, 36, 180, 132, 145,
+ 14, 135, 237, 216, 209, 197, 26, 102, 242, 210, 225, 176, 209, 115, 38,
+ 56, 29, 49, 240, 253, 80, 167, 82, 162, 152, 59, 29, 86, 9, 117,
+ 76, 156, 239, 179, 167, 83, 237, 162, 90, 123, 88, 196, 45, 46, 117,
+ 245, 40, 205, 213, 3, 104, 63, 77, 71, 76, 145, 188, 117, 188, 223,
+ 196, 127, 79, 15, 239, 251, 208, 190, 120, 83, 29, 5, 12, 116, 248,
+ 113, 58, 44, 154, 78, 229, 155, 23, 202, 91, 71, 219, 125, 243, 183,
+ 213, 89, 176, 164, 153, 212, 161, 128, 105, 61, 166, 105, 62, 90, 79,
+ 177, 170, 122, 38, 185, 222, 246, 218, 152, 115, 205, 92, 73, 103, 233,
+ 60, 238, 165, 96, 37, 186, 83, 122, 246, 245, 133, 114, 30, 46, 161,
+ 235, 99, 78, 211, 124, 249, 127, 203, 187, 248, 252, 47, 122, 23, 196,
+ 134, 254, 93, 28, 220, 125, 178, 14, 27, 123, 23, 135, 205, 252, 93,
+ 28, 54, 246, 46, 42, 173, 190, 139, 195, 102, 246, 46, 223, 121, 169,
+ 24, 170, 167, 120, 86, 222, 118, 25, 217, 99, 149, 206, 46, 195, 44,
+ 175, 88, 28, 150, 38, 150, 37, 150, 214, 44, 7, 117, 127, 39, 249,
+ 243, 246, 101, 219, 230, 182, 139, 151, 173, 135, 252, 202, 208, 155, 191,
+ 25, 189, 139, 87, 114, 79, 121, 236, 137, 47, 180, 62, 93, 136, 92,
+ 240, 217, 120, 37, 182, 20, 182, 245, 150, 111, 45, 56, 108, 56, 158,
+ 41, 146, 220, 71, 110, 148, 213, 76, 139, 149, 253, 228, 55, 254, 94,
+ 160, 208, 245, 18, 251, 203, 206, 105, 52, 135, 218, 45, 111, 147, 14,
+ 239, 201, 101, 10, 70, 104, 101, 66, 229, 133, 41, 106, 62, 251, 91,
+ 109, 135, 203, 94, 247, 203, 26, 222, 223, 120, 113, 255, 88, 185, 145,
+ 125, 132, 86, 102, 146, 60, 54, 92, 221, 163, 123, 190, 141, 67, 254,
+ 178, 229, 97, 67, 222, 156, 253, 243, 229, 194, 157, 125, 246, 168, 79,
+ 151, 80, 250, 173, 65, 95, 112, 207, 141, 191, 27, 182, 75, 228, 187,
+ 133, 142, 157, 97, 75, 88, 152, 216, 58, 247, 119, 11, 253, 98, 129,
+ 109, 84, 246, 122, 118, 198, 7, 124, 51, 252, 69, 194, 175, 128, 218,
+ 82, 121, 47, 216, 215, 73, 238, 59, 183, 122, 187, 220, 223, 173, 27,
+ 124, 183, 222, 99, 179, 13, 109, 239, 13, 223, 45, 248, 80, 209, 68,
+ 242, 221, 66, 166, 118, 85, 232, 204, 246, 189, 229, 30, 229, 62, 54,
+ 180, 125, 182, 179, 143, 156, 146, 180, 41, 145, 124, 183, 211, 87, 15,
+ 41, 244, 195, 132, 254, 242, 221, 31, 140, 109, 127, 69, 126, 79, 78,
+ 187, 244, 122, 18, 249, 110, 77, 166, 169, 123, 186, 143, 180, 25, 46,
+ 59, 7, 173, 54, 228, 253, 2, 190, 219, 216, 173, 251, 233, 119, 59,
+ 95, 234, 162, 66, 255, 2, 223, 109, 208, 149, 98, 134, 182, 127, 4,
+ 223, 109, 230, 4, 127, 250, 221, 8, 221, 31, 190, 27, 123, 110, 252,
+ 221, 176, 173, 55, 195, 219, 168, 92, 120, 27, 170, 125, 183, 37, 240,
+ 163, 57, 193, 128, 183, 148, 204, 38, 187, 220, 225, 109, 195, 254, 146,
+ 175, 25, 189, 203, 11, 103, 79, 121, 226, 224, 166, 109, 200, 119, 187,
+ 80, 185, 123, 27, 149, 183, 183, 252, 250, 137, 225, 109, 140, 121, 251,
+ 200, 53, 83, 3, 218, 144, 239, 54, 229, 86, 21, 133, 246, 6, 188,
+ 221, 111, 115, 220, 80, 239, 115, 248, 110, 227, 223, 248, 250, 53, 242,
+ 221, 86, 6, 141, 87, 232, 130, 128, 183, 140, 226, 87, 90, 27, 241,
+ 62, 131, 239, 86, 184, 190, 119, 107, 242, 221, 42, 117, 252, 202, 170,
+ 242, 58, 228, 87, 235, 70, 237, 52, 230, 157, 47, 191, 17, 176, 178,
+ 41, 249, 110, 132, 238, 1, 223, 141, 61, 55, 158, 223, 192, 190, 38,
+ 157, 19, 244, 130, 126, 78, 186, 81, 191, 179, 153, 174, 223, 233, 44,
+ 152, 225, 237, 44, 96, 222, 239, 196, 114, 116, 207, 78, 65, 214, 39,
+ 8, 41, 224, 105, 63, 199, 253, 248, 3, 219, 20, 186, 103, 135, 211,
+ 129, 239, 228, 212, 244, 184, 188, 61, 237, 231, 120, 185, 237, 231, 160,
+ 255, 211, 122, 20, 208, 247, 115, 72, 93, 194, 188, 61, 237, 231, 184,
+ 175, 7, 126, 43, 58, 191, 86, 32, 67, 119, 190, 60, 107, 55, 29,
+ 54, 66, 175, 178, 37, 216, 141, 218, 83, 221, 217, 224, 222, 122, 121,
+ 12, 207, 14, 27, 161, 151, 133, 236, 182, 27, 225, 92, 183, 54, 155,
+ 75, 30, 243, 51, 135, 141, 208, 171, 225, 253, 140, 252, 143, 31, 247,
+ 160, 207, 209, 61, 54, 17, 25, 222, 118, 174, 207, 248, 178, 255, 53,
+ 215, 249, 95, 24, 250, 171, 197, 220, 255, 176, 28, 157, 151, 178, 48,
+ 249, 113, 179, 197, 249, 31, 202, 165, 227, 30, 160, 81, 167, 226, 35,
+ 179, 197, 249, 95, 152, 69, 239, 127, 164, 46, 41, 17, 226, 252, 15,
+ 109, 194, 159, 211, 230, 206, 255, 66, 43, 172, 240, 216, 255, 236, 156,
+ 60, 251, 160, 34, 110, 253, 47, 12, 228, 121, 234, 127, 88, 87, 34,
+ 207, 1, 239, 231, 206, 255, 82, 124, 87, 120, 236, 127, 232, 115, 116,
+ 255, 253, 204, 12, 239, 52, 47, 35, 255, 107, 161, 243, 191, 148, 240,
+ 12, 239, 148, 89, 230, 254, 135, 229, 232, 26, 95, 56, 147, 31, 58,
+ 75, 156, 255, 133, 112, 58, 240, 157, 82, 52, 61, 105, 51, 197, 249,
+ 31, 202, 213, 173, 241, 105, 58, 28, 51, 197, 249, 31, 218, 36, 191,
+ 254, 167, 91, 227, 155, 153, 127, 255, 211, 173, 241, 205, 204, 191, 255,
+ 241, 241, 23, 125, 142, 198, 223, 137, 25, 222, 33, 17, 70, 254, 215,
+ 82, 231, 127, 142, 25, 25, 222, 142, 169, 230, 254, 135, 229, 232, 119,
+ 155, 193, 228, 251, 76, 245, 116, 222, 199, 203, 116, 190, 196, 194, 233,
+ 112, 76, 135, 247, 210, 244, 196, 76, 241, 116, 222, 199, 92, 7, 202,
+ 165, 245, 0, 154, 212, 197, 58, 197, 211, 121, 31, 15, 234, 193, 233,
+ 112, 76, 131, 122, 76, 215, 230, 50, 38, 123, 58, 239, 227, 101, 58,
+ 239, 131, 114, 105, 61, 128, 182, 104, 58, 66, 38, 231, 175, 61, 208,
+ 213, 131, 211, 129, 62, 130, 58, 149, 254, 208, 164, 252, 181, 7, 186,
+ 239, 49, 85, 223, 30, 88, 52, 29, 97, 147, 242, 215, 30, 16, 29,
+ 193, 154, 143, 242, 120, 115, 55, 174, 24, 234, 216, 99, 55, 154, 223,
+ 208, 173, 157, 76, 17, 43, 207, 42, 88, 30, 250, 153, 94, 222, 203,
+ 115, 40, 170, 60, 135, 205, 19, 121, 33, 188, 188, 111, 11, 58, 167,
+ 125, 80, 114, 79, 238, 247, 75, 123, 88, 207, 62, 115, 201, 103, 237,
+ 243, 154, 7, 209, 245, 39, 39, 113, 237, 243, 255, 231, 248, 92, 215,
+ 159, 156, 164, 175, 111, 244, 161, 79, 155, 229, 150, 103, 143, 171, 99,
+ 143, 62, 84, 42, 62, 175, 113, 163, 174, 63, 57, 145, 139, 231, 149,
+ 192, 15, 103, 26, 181, 167, 173, 244, 253, 73, 224, 13, 11, 243, 160,
+ 63, 57, 145, 235, 79, 126, 196, 249, 122, 77, 79, 219, 211, 130, 166,
+ 237, 16, 202, 165, 253, 73, 160, 81, 167, 130, 223, 87, 60, 109, 79,
+ 205, 117, 132, 113, 58, 210, 38, 64, 223, 71, 171, 139, 179, 186, 167,
+ 237, 169, 7, 245, 152, 192, 213, 3, 232, 48, 77, 71, 76, 53, 79,
+ 219, 211, 130, 166, 237, 105, 24, 167, 35, 13, 190, 31, 234, 84, 252,
+ 166, 170, 167, 237, 105, 33, 183, 237, 16, 150, 161, 245, 8, 227, 234,
+ 1, 116, 152, 166, 195, 85, 217, 211, 246, 180, 144, 219, 246, 20, 203,
+ 208, 122, 132, 229, 234, 223, 135, 105, 253, 171, 74, 158, 182, 167, 238,
+ 235, 129, 255, 79, 239, 246, 172, 153, 65, 239, 246, 196, 92, 110, 119,
+ 237, 21, 230, 114, 231, 110, 175, 154, 88, 2, 94, 58, 47, 77, 255,
+ 46, 234, 159, 95, 234, 32, 211, 185, 230, 180, 242, 75, 185, 50, 177,
+ 148, 30, 247, 236, 132, 41, 111, 116, 57, 11, 55, 31, 237, 75, 233,
+ 189, 95, 7, 202, 102, 188, 196, 6, 136, 161, 255, 235, 54, 64, 140,
+ 255, 95, 183, 1, 182, 65, 122, 27, 188, 28, 107, 85, 27, 232, 99,
+ 109, 19, 139, 175, 215, 203, 54, 112, 216, 152, 13, 84, 90, 181, 129,
+ 241, 90, 135, 106, 3, 118, 174, 1, 161, 85, 27, 24, 243, 170, 54,
+ 112, 216, 152, 13, 84, 90, 181, 129, 49, 47, 218, 32, 200, 75, 109,
+ 35, 235, 41, 45, 7, 188, 249, 217, 91, 118, 108, 243, 72, 61, 8,
+ 125, 37, 125, 144, 196, 158, 147, 179, 29, 94, 177, 116, 128, 31, 145,
+ 183, 115, 244, 82, 169, 219, 116, 210, 183, 96, 223, 114, 118, 210, 118,
+ 201, 246, 99, 222, 125, 11, 197, 126, 61, 246, 73, 115, 27, 47, 212,
+ 222, 55, 69, 58, 219, 104, 155, 66, 103, 31, 248, 87, 106, 114, 249,
+ 50, 173, 199, 90, 75, 31, 203, 102, 203, 251, 150, 68, 203, 40, 202,
+ 59, 184, 229, 3, 41, 115, 70, 97, 226, 131, 242, 230, 86, 215, 148,
+ 242, 203, 23, 22, 150, 51, 75, 239, 165, 188, 127, 90, 38, 89, 46,
+ 1, 95, 154, 37, 148, 157, 117, 240, 71, 41, 185, 204, 7, 229, 119,
+ 17, 251, 17, 186, 240, 91, 213, 184, 231, 216, 160, 54, 177, 148, 134,
+ 95, 13, 175, 38, 47, 217, 15, 219, 127, 98, 191, 110, 255, 221, 178,
+ 99, 123, 78, 236, 71, 232, 42, 155, 103, 72, 236, 57, 218, 175, 153,
+ 114, 110, 114, 111, 248, 145, 245, 138, 209, 167, 54, 74, 172, 47, 197,
+ 236, 247, 214, 170, 88, 201, 108, 173, 99, 109, 145, 157, 82, 135, 83,
+ 123, 146, 136, 253, 98, 254, 78, 80, 232, 70, 79, 92, 210, 181, 93,
+ 187, 232, 186, 193, 231, 150, 58, 96, 191, 58, 150, 61, 240, 35, 188,
+ 222, 33, 233, 82, 249, 213, 123, 216, 185, 161, 45, 39, 43, 107, 38,
+ 213, 27, 148, 147, 49, 118, 17, 222, 147, 150, 32, 229, 44, 149, 98,
+ 94, 237, 41, 239, 251, 203, 202, 203, 246, 97, 51, 127, 35, 246, 35,
+ 116, 147, 65, 213, 184, 231, 22, 75, 41, 206, 126, 132, 151, 216, 15,
+ 99, 27, 177, 95, 107, 176, 31, 198, 42, 98, 63, 66, 35, 142, 216,
+ 115, 180, 95, 45, 176, 95, 19, 240, 191, 38, 58, 28, 157, 250, 143,
+ 244, 29, 153, 253, 138, 78, 217, 14, 207, 243, 238, 59, 34, 111, 214,
+ 130, 125, 210, 180, 232, 162, 219, 136, 253, 138, 252, 108, 85, 232, 226,
+ 25, 255, 74, 85, 82, 67, 183, 49, 255, 107, 2, 246, 107, 2, 254,
+ 199, 120, 31, 151, 120, 32, 253, 178, 126, 30, 41, 35, 143, 174, 56,
+ 120, 155, 58, 127, 95, 88, 254, 98, 191, 109, 27, 243, 191, 38, 96,
+ 191, 38, 150, 251, 186, 181, 142, 82, 242, 200, 42, 206, 70, 196, 126,
+ 132, 238, 1, 246, 99, 207, 221, 251, 31, 157, 63, 168, 196, 250, 187,
+ 113, 229, 161, 239, 51, 209, 168, 191, 219, 90, 63, 127, 80, 17, 198,
+ 133, 21, 60, 152, 63, 168, 200, 245, 75, 42, 114, 243, 7, 21, 196,
+ 205, 95, 89, 56, 29, 248, 78, 14, 77, 79, 140, 175, 184, 249, 43,
+ 148, 171, 27, 175, 106, 58, 172, 190, 226, 230, 175, 208, 38, 34, 231,
+ 79, 177, 254, 34, 231, 79, 173, 190, 98, 231, 79, 209, 231, 232, 61,
+ 28, 189, 192, 142, 149, 140, 252, 239, 53, 157, 255, 89, 129, 215, 90,
+ 206, 220, 255, 176, 28, 221, 35, 87, 142, 201, 119, 150, 21, 231, 127,
+ 40, 151, 238, 245, 3, 26, 117, 42, 115, 50, 101, 197, 249, 159, 181,
+ 156, 222, 255, 72, 93, 92, 62, 226, 252, 15, 109, 34, 114, 254, 52,
+ 164, 172, 216, 249, 83, 172, 171, 200, 249, 83, 244, 57, 186, 126, 212,
+ 61, 195, 59, 174, 188, 129, 255, 53, 181, 234, 252, 207, 15, 120, 253,
+ 122, 154, 251, 31, 150, 163, 251, 180, 122, 114, 235, 71, 61, 196, 249,
+ 31, 202, 165, 251, 180, 128, 70, 157, 74, 255, 179, 135, 56, 255, 243,
+ 235, 153, 107, 159, 150, 86, 151, 148, 238, 2, 215, 143, 122, 8, 94,
+ 63, 234, 33, 120, 253, 168, 187, 224, 245, 163, 238, 220, 124, 83, 151,
+ 12, 239, 152, 94, 70, 254, 167, 223, 183, 153, 210, 45, 195, 59, 165,
+ 171, 7, 235, 71, 221, 184, 245, 163, 110, 220, 250, 81, 87, 129, 235,
+ 71, 156, 14, 124, 167, 20, 77, 79, 90, 23, 129, 235, 71, 93, 115,
+ 173, 31, 105, 58, 28, 93, 4, 174, 31, 117, 21, 188, 126, 212, 69,
+ 240, 250, 81, 23, 193, 235, 71, 93, 184, 254, 95, 167, 12, 239, 144,
+ 238, 70, 254, 167, 223, 191, 225, 120, 3, 250, 89, 175, 123, 208, 255,
+ 123, 131, 251, 110, 111, 112, 253, 191, 215, 5, 246, 255, 56, 29, 248,
+ 78, 14, 77, 79, 76, 103, 129, 253, 191, 215, 115, 245, 255, 52, 29,
+ 214, 206, 2, 251, 127, 175, 11, 238, 255, 117, 22, 220, 255, 235, 44,
+ 184, 255, 215, 137, 249, 159, 143, 12, 118, 236, 226, 198, 255, 180, 60,
+ 143, 49, 195, 134, 235, 251, 127, 192, 27, 215, 33, 195, 52, 63, 10,
+ 203, 209, 254, 95, 71, 38, 63, 90, 206, 107, 14, 217, 98, 119, 55,
+ 223, 158, 251, 187, 61, 250, 47, 188, 29, 237, 255, 117, 228, 250, 127,
+ 64, 163, 78, 165, 208, 120, 79, 116, 84, 203, 83, 199, 245, 153, 237,
+ 232, 189, 130, 86, 78, 7, 214, 155, 212, 197, 53, 214, 19, 29, 213,
+ 243, 212, 177, 180, 109, 203, 36, 90, 143, 14, 122, 31, 183, 106, 58,
+ 156, 99, 140, 116, 188, 60, 223, 254, 82, 206, 74, 163, 153, 54, 50,
+ 111, 134, 118, 39, 243, 102, 184, 215, 15, 237, 72, 228, 17, 186, 247,
+ 154, 185, 18, 123, 238, 190, 13, 59, 255, 115, 41, 249, 68, 90, 61,
+ 186, 71, 147, 148, 47, 153, 241, 142, 124, 96, 238, 2, 67, 222, 71,
+ 37, 198, 202, 55, 27, 111, 213, 202, 204, 146, 165, 38, 123, 181, 243,
+ 164, 163, 228, 148, 185, 39, 12, 121, 115, 10, 44, 144, 255, 110, 120,
+ 169, 29, 217, 55, 71, 232, 176, 27, 203, 184, 231, 121, 183, 227, 105,
+ 154, 95, 240, 54, 192, 239, 76, 108, 64, 104, 220, 235, 204, 158, 187,
+ 151, 247, 15, 216, 32, 34, 120, 96, 34, 177, 1, 41, 95, 28, 108,
+ 208, 112, 112, 75, 67, 222, 199, 96, 131, 118, 195, 171, 38, 18, 27,
+ 52, 218, 171, 238, 89, 69, 27, 220, 123, 254, 36, 193, 204, 6, 187,
+ 238, 157, 76, 32, 54, 32, 52, 218, 128, 61, 55, 182, 1, 250, 45,
+ 111, 3, 244, 67, 98, 3, 66, 15, 7, 27, 176, 231, 238, 229, 149,
+ 140, 47, 37, 23, 252, 37, 50, 137, 216, 128, 148, 111, 4, 54, 24,
+ 56, 181, 118, 146, 153, 31, 148, 143, 59, 64, 109, 208, 239, 143, 48,
+ 133, 246, 2, 27, 116, 221, 85, 44, 209, 204, 6, 129, 99, 98, 218,
+ 18, 27, 16, 122, 2, 216, 128, 61, 55, 182, 1, 226, 138, 183, 1,
+ 226, 132, 216, 128, 208, 232, 7, 236, 121, 222, 126, 112, 183, 208, 116,
+ 186, 231, 157, 148, 71, 63, 24, 18, 111, 204, 139, 54, 72, 220, 65,
+ 206, 63, 157, 37, 251, 201, 234, 121, 166, 232, 7, 191, 126, 19, 97,
+ 51, 179, 65, 249, 247, 72, 153, 37, 148, 70, 63, 96, 207, 141, 251,
+ 32, 216, 238, 211, 179, 229, 70, 66, 187, 214, 201, 48, 6, 40, 249,
+ 75, 116, 15, 37, 216, 207, 249, 161, 121, 12, 192, 114, 116, 127, 231,
+ 104, 110, 15, 233, 135, 158, 198, 0, 247, 177, 27, 241, 78, 247, 119,
+ 142, 230, 246, 169, 2, 109, 215, 218, 76, 215, 40, 79, 99, 128, 123,
+ 29, 136, 39, 90, 15, 78, 7, 214, 155, 212, 37, 108, 148, 167, 49,
+ 192, 189, 14, 244, 87, 90, 143, 15, 115, 237, 83, 37, 246, 26, 229,
+ 105, 12, 112, 175, 3, 253, 129, 206, 11, 124, 168, 223, 7, 202, 218,
+ 77, 135, 141, 208, 219, 236, 9, 118, 163, 246, 84, 183, 175, 96, 148,
+ 94, 30, 107, 131, 28, 54, 66, 163, 60, 163, 182, 73, 183, 175, 32,
+ 151, 60, 134, 103, 135, 141, 208, 241, 32, 207, 8, 231, 186, 51, 132,
+ 114, 201, 99, 216, 112, 216, 8, 141, 239, 103, 132, 25, 190, 223, 132,
+ 56, 161, 249, 126, 67, 129, 150, 205, 48, 195, 242, 202, 45, 192, 235,
+ 24, 110, 142, 25, 44, 71, 251, 212, 35, 184, 126, 251, 112, 113, 152,
+ 65, 185, 212, 215, 80, 199, 72, 173, 223, 62, 76, 28, 102, 44, 156,
+ 14, 172, 55, 169, 139, 117, 152, 56, 204, 160, 92, 221, 216, 64, 211,
+ 225, 28, 42, 14, 51, 104, 119, 62, 103, 212, 29, 102, 48, 103, 212,
+ 83, 204, 160, 141, 121, 121, 238, 48, 131, 242, 60, 197, 140, 53, 151,
+ 60, 119, 152, 241, 3, 121, 158, 98, 6, 109, 199, 203, 115, 135, 25,
+ 124, 63, 79, 49, 163, 224, 132, 200, 27, 4, 126, 48, 210, 12, 51,
+ 44, 175, 220, 57, 4, 218, 243, 193, 230, 152, 193, 114, 52, 6, 12,
+ 97, 242, 173, 54, 79, 49, 83, 192, 20, 51, 118, 78, 135, 19, 222,
+ 201, 169, 233, 177, 183, 247, 20, 51, 5, 76, 49, 131, 114, 105, 61,
+ 128, 38, 117, 9, 105, 231, 41, 102, 10, 152, 98, 198, 62, 88, 143,
+ 25, 212, 169, 140, 111, 131, 61, 197, 76, 1, 67, 204, 108, 215, 236,
+ 94, 79, 27, 215, 123, 239, 124, 152, 228, 14, 51, 23, 198, 150, 183,
+ 155, 245, 219, 135, 223, 13, 179, 63, 255, 120, 151, 86, 38, 198, 126,
+ 114, 82, 178, 66, 191, 82, 37, 222, 126, 60, 102, 191, 33, 222, 74,
+ 252, 118, 132, 147, 239, 162, 116, 226, 215, 143, 237, 158, 140, 23, 182,
+ 107, 223, 150, 212, 227, 246, 175, 15, 147, 220, 97, 245, 44, 212, 195,
+ 172, 239, 61, 0, 234, 145, 232, 53, 108, 55, 169, 199, 187, 221, 50,
+ 21, 186, 57, 212, 195, 254, 69, 101, 67, 156, 151, 130, 122, 48, 249,
+ 46, 74, 239, 134, 122, 120, 210, 231, 223, 174, 249, 15, 169, 199, 181,
+ 239, 31, 38, 185, 107, 35, 26, 140, 46, 111, 55, 235, 63, 23, 114,
+ 133, 217, 167, 142, 105, 145, 68, 234, 113, 227, 245, 242, 10, 221, 160,
+ 81, 188, 253, 104, 169, 130, 73, 70, 245, 168, 182, 251, 8, 39, 223,
+ 69, 233, 123, 171, 31, 219, 61, 233, 183, 111, 215, 124, 148, 212, 163,
+ 30, 248, 149, 187, 182, 233, 10, 124, 15, 179, 62, 176, 3, 190, 71,
+ 47, 218, 63, 143, 177, 127, 25, 164, 222, 85, 240, 168, 114, 188, 253,
+ 243, 161, 179, 12, 219, 181, 34, 240, 61, 152, 124, 23, 165, 157, 240,
+ 61, 60, 237, 123, 99, 59, 72, 239, 232, 107, 13, 56, 31, 106, 214,
+ 38, 178, 251, 3, 92, 109, 51, 188, 67, 219, 152, 183, 137, 88, 142,
+ 222, 159, 215, 150, 201, 79, 123, 45, 127, 253, 8, 126, 254, 37, 148,
+ 211, 225, 130, 119, 114, 105, 122, 28, 175, 229, 175, 31, 193, 207, 191,
+ 160, 92, 90, 15, 160, 73, 93, 124, 94, 203, 95, 63, 130, 159, 127,
+ 9, 109, 163, 111, 19, 81, 167, 226, 25, 173, 243, 215, 143, 32, 243,
+ 47, 193, 154, 221, 73, 92, 109, 24, 90, 196, 249, 124, 80, 151, 151,
+ 230, 95, 124, 156, 39, 108, 217, 173, 230, 122, 212, 143, 112, 112, 242,
+ 156, 32, 111, 70, 252, 240, 151, 230, 50, 162, 147, 79, 216, 54, 182,
+ 203, 123, 62, 66, 119, 222, 13, 39, 47, 109, 36, 200, 43, 212, 250,
+ 165, 121, 1, 215, 129, 19, 182, 189, 155, 91, 36, 121, 212, 207, 105,
+ 205, 228, 69, 195, 251, 245, 253, 112, 198, 75, 99, 236, 80, 168, 111,
+ 145, 55, 103, 122, 212, 143, 64, 156, 16, 204, 184, 154, 66, 252, 29,
+ 100, 134, 25, 118, 127, 64, 204, 171, 25, 222, 126, 173, 204, 49, 131,
+ 229, 232, 122, 222, 171, 220, 154, 77, 51, 79, 49, 83, 198, 173, 31,
+ 164, 93, 14, 161, 119, 78, 250, 113, 58, 98, 224, 157, 98, 52, 61,
+ 161, 239, 121, 138, 25, 247, 58, 124, 127, 237, 65, 117, 160, 92, 90,
+ 15, 160, 73, 93, 98, 6, 120, 138, 25, 247, 58, 70, 149, 60, 78,
+ 251, 17, 126, 173, 114, 173, 75, 182, 210, 198, 221, 253, 60, 197, 140,
+ 123, 29, 155, 158, 171, 231, 211, 204, 45, 160, 218, 189, 158, 82, 82,
+ 221, 235, 135, 118, 36, 242, 8, 253, 70, 220, 28, 59, 123, 238, 190,
+ 221, 189, 218, 235, 153, 253, 76, 219, 42, 244, 126, 176, 95, 255, 236,
+ 164, 148, 31, 144, 58, 72, 242, 122, 220, 212, 240, 220, 193, 167, 229,
+ 151, 74, 12, 171, 177, 116, 126, 212, 235, 217, 102, 201, 8, 171, 22,
+ 229, 110, 202, 109, 82, 141, 113, 81, 90, 153, 157, 82, 249, 209, 31,
+ 43, 52, 222, 107, 89, 98, 228, 66, 147, 249, 206, 125, 210, 130, 107,
+ 203, 232, 221, 123, 155, 162, 190, 162, 247, 90, 30, 173, 185, 206, 144,
+ 215, 82, 240, 148, 84, 233, 242, 70, 122, 247, 222, 231, 235, 227, 212,
+ 121, 214, 136, 179, 210, 25, 239, 29, 198, 122, 35, 47, 72, 181, 247,
+ 36, 208, 187, 247, 90, 212, 85, 251, 92, 94, 17, 151, 37, 121, 193,
+ 1, 67, 94, 175, 168, 107, 82, 86, 193, 67, 244, 94, 203, 26, 29,
+ 143, 169, 115, 195, 17, 183, 165, 129, 115, 78, 26, 242, 214, 138, 186,
+ 43, 69, 251, 166, 210, 123, 45, 251, 79, 191, 161, 208, 221, 34, 210,
+ 165, 93, 174, 71, 134, 188, 225, 81, 153, 210, 202, 187, 69, 181, 125,
+ 111, 89, 82, 237, 113, 85, 21, 122, 72, 68, 182, 116, 58, 35, 176,
+ 189, 17, 239, 127, 142, 28, 105, 228, 67, 122, 199, 183, 236, 172, 212,
+ 95, 161, 71, 219, 188, 228, 167, 109, 7, 24, 242, 166, 58, 189, 229,
+ 22, 161, 77, 181, 50, 5, 101, 231, 136, 90, 10, 189, 54, 188, 176,
+ 188, 123, 182, 151, 33, 239, 209, 200, 98, 242, 107, 235, 137, 77, 74,
+ 202, 242, 37, 245, 27, 61, 108, 95, 74, 254, 219, 59, 198, 120, 30,
+ 221, 89, 90, 110, 255, 234, 231, 90, 25, 31, 57, 120, 139, 234, 75,
+ 57, 237, 203, 202, 11, 235, 204, 49, 228, 125, 225, 44, 39, 179, 57,
+ 126, 95, 74, 159, 159, 94, 65, 54, 155, 251, 167, 184, 124, 79, 143,
+ 75, 108, 123, 8, 46, 9, 253, 58, 224, 146, 61, 119, 47, 239, 18,
+ 224, 178, 204, 124, 255, 96, 130, 75, 239, 61, 146, 82, 190, 27, 222,
+ 45, 214, 171, 172, 97, 223, 246, 38, 224, 146, 197, 188, 88, 58, 103,
+ 95, 5, 112, 105, 20, 243, 144, 183, 72, 193, 109, 82, 114, 15, 47,
+ 122, 111, 95, 145, 183, 127, 81, 116, 21, 3, 92, 190, 26, 216, 207,
+ 80, 239, 35, 192, 101, 220, 165, 154, 109, 8, 46, 79, 76, 246, 83,
+ 222, 255, 217, 211, 163, 82, 250, 228, 213, 134, 109, 73, 118, 129, 83,
+ 210, 43, 247, 110, 4, 19, 92, 222, 93, 86, 158, 222, 55, 219, 101,
+ 112, 29, 67, 219, 63, 5, 92, 246, 216, 100, 167, 184, 60, 18, 244,
+ 154, 66, 215, 6, 92, 62, 216, 218, 212, 144, 183, 24, 224, 242, 183,
+ 20, 111, 138, 203, 35, 255, 170, 247, 190, 122, 1, 46, 253, 170, 125,
+ 108, 248, 206, 87, 34, 239, 74, 251, 31, 173, 108, 75, 112, 249, 247,
+ 187, 23, 148, 61, 162, 15, 194, 211, 165, 253, 43, 182, 237, 54, 110,
+ 75, 50, 165, 216, 175, 246, 237, 38, 184, 188, 115, 168, 104, 130, 218,
+ 14, 101, 75, 243, 247, 55, 49, 180, 243, 139, 200, 28, 233, 210, 221,
+ 209, 164, 140, 188, 114, 203, 167, 10, 237, 5, 184, 180, 13, 253, 222,
+ 144, 23, 239, 196, 108, 244, 233, 254, 4, 130, 203, 255, 126, 79, 85,
+ 233, 136, 194, 242, 170, 181, 22, 67, 223, 192, 187, 197, 46, 220, 47,
+ 71, 239, 237, 107, 240, 101, 109, 149, 182, 149, 146, 223, 24, 19, 96,
+ 204, 11, 184, 44, 115, 187, 69, 34, 193, 229, 46, 223, 215, 52, 222,
+ 178, 242, 32, 155, 241, 154, 18, 226, 146, 173, 59, 249, 82, 26, 113,
+ 105, 182, 30, 69, 112, 137, 241, 157, 224, 114, 1, 224, 18, 227, 53,
+ 193, 37, 161, 151, 3, 46, 217, 115, 247, 242, 222, 234, 253, 204, 238,
+ 119, 147, 248, 163, 85, 10, 12, 216, 167, 148, 47, 112, 118, 144, 20,
+ 212, 245, 186, 161, 237, 47, 151, 3, 92, 210, 190, 99, 44, 93, 71,
+ 250, 0, 112, 105, 212, 119, 84, 244, 226, 157, 127, 125, 171, 37, 17,
+ 92, 118, 169, 85, 72, 161, 223, 6, 92, 158, 251, 251, 130, 161, 13,
+ 110, 2, 46, 219, 95, 251, 60, 145, 224, 114, 76, 117, 155, 66, 223,
+ 4, 92, 70, 92, 141, 51, 124, 231, 58, 16, 47, 119, 15, 113, 180,
+ 37, 184, 252, 115, 172, 122, 159, 116, 81, 192, 101, 211, 210, 141, 12,
+ 177, 181, 14, 112, 185, 224, 239, 69, 20, 151, 39, 187, 170, 49, 62,
+ 21, 112, 89, 38, 209, 97, 200, 123, 41, 242, 154, 116, 125, 241, 3,
+ 122, 87, 109, 131, 170, 125, 20, 122, 95, 248, 109, 105, 195, 227, 25,
+ 134, 216, 186, 7, 184, 140, 158, 251, 52, 129, 224, 50, 112, 205, 79,
+ 10, 61, 221, 145, 46, 85, 59, 211, 217, 176, 190, 71, 33, 94, 150,
+ 95, 84, 149, 222, 167, 233, 31, 171, 246, 51, 240, 174, 218, 87, 170,
+ 159, 53, 238, 91, 204, 206, 145, 46, 23, 10, 162, 241, 178, 92, 231,
+ 38, 10, 157, 6, 184, 60, 60, 183, 153, 97, 204, 171, 152, 236, 45,
+ 91, 143, 61, 110, 71, 112, 57, 229, 59, 181, 159, 177, 15, 226, 165,
+ 99, 115, 73, 67, 189, 159, 2, 46, 165, 14, 165, 41, 46, 67, 135,
+ 111, 81, 232, 61, 16, 47, 27, 76, 118, 25, 250, 198, 74, 192, 101,
+ 249, 138, 165, 147, 8, 46, 123, 156, 175, 174, 208, 201, 16, 47, 247,
+ 125, 21, 104, 232, 147, 143, 1, 151, 108, 45, 212, 151, 210, 151, 0,
+ 151, 102, 107, 164, 4, 151, 216, 39, 230, 227, 37, 246, 113, 9, 46,
+ 9, 141, 57, 43, 236, 185, 123, 121, 7, 32, 94, 214, 155, 193, 114,
+ 86, 142, 105, 229, 235, 67, 188, 12, 41, 102, 204, 123, 15, 226, 37,
+ 27, 131, 197, 210, 181, 205, 194, 128, 75, 163, 49, 152, 218, 23, 221,
+ 6, 254, 50, 139, 222, 197, 249, 119, 11, 237, 174, 70, 192, 229, 234,
+ 127, 195, 13, 121, 159, 2, 46, 183, 239, 140, 160, 119, 113, 70, 100,
+ 147, 117, 206, 163, 210, 27, 193, 179, 77, 244, 158, 146, 170, 84, 158,
+ 77, 239, 226, 140, 216, 31, 161, 221, 17, 121, 86, 138, 251, 202, 120,
+ 174, 229, 57, 224, 242, 65, 25, 58, 79, 35, 253, 81, 156, 240, 94,
+ 150, 214, 21, 50, 227, 189, 38, 221, 93, 16, 65, 239, 226, 124, 255,
+ 107, 194, 123, 91, 58, 22, 103, 204, 251, 2, 112, 217, 122, 69, 4,
+ 189, 139, 243, 122, 119, 149, 46, 2, 253, 216, 229, 5, 140, 121, 125,
+ 1, 151, 7, 78, 176, 187, 56, 87, 13, 81, 109, 254, 10, 196, 203,
+ 222, 143, 103, 24, 242, 158, 130, 120, 153, 29, 57, 133, 222, 197, 217,
+ 112, 176, 74, 151, 5, 92, 246, 151, 167, 24, 242, 62, 132, 120, 185,
+ 113, 248, 12, 122, 23, 103, 167, 213, 170, 63, 60, 0, 92, 190, 83,
+ 208, 248, 157, 159, 2, 46, 203, 116, 101, 119, 113, 254, 123, 91, 243,
+ 13, 136, 151, 157, 119, 27, 251, 6, 198, 203, 82, 95, 18, 191, 242,
+ 145, 71, 214, 32, 247, 135, 150, 149, 247, 127, 103, 236, 147, 24, 47,
+ 217, 250, 188, 47, 165, 49, 94, 154, 173, 219, 147, 57, 5, 156, 71,
+ 160, 243, 112, 189, 97, 156, 220, 218, 108, 78, 129, 221, 21, 21, 10,
+ 188, 161, 125, 205, 231, 20, 176, 28, 157, 191, 226, 198, 198, 105, 125,
+ 196, 173, 231, 161, 92, 58, 15, 7, 239, 132, 58, 21, 105, 125, 196,
+ 173, 231, 161, 92, 90, 15, 212, 161, 213, 197, 167, 143, 184, 245, 188,
+ 208, 190, 185, 230, 225, 250, 106, 243, 22, 189, 197, 173, 231, 161, 221,
+ 69, 174, 231, 57, 250, 136, 93, 207, 243, 233, 35, 118, 61, 15, 109,
+ 39, 114, 61, 15, 113, 66, 231, 225, 2, 51, 188, 93, 77, 205, 48,
+ 195, 238, 138, 138, 105, 2, 24, 107, 236, 193, 60, 92, 19, 110, 254,
+ 170, 9, 183, 119, 191, 145, 56, 204, 248, 113, 58, 98, 224, 157, 98,
+ 52, 61, 246, 70, 226, 48, 131, 114, 105, 61, 128, 38, 117, 73, 9,
+ 18, 135, 25, 191, 198, 185, 230, 225, 26, 107, 243, 137, 65, 226, 48,
+ 131, 118, 207, 47, 102, 44, 252, 125, 104, 141, 242, 143, 25, 94, 30,
+ 218, 51, 191, 152, 225, 229, 133, 6, 229, 31, 51, 186, 56, 19, 200,
+ 229, 91, 53, 0, 63, 232, 109, 134, 25, 118, 87, 84, 40, 98, 204,
+ 223, 131, 56, 19, 200, 197, 128, 0, 38, 63, 204, 95, 28, 102, 80,
+ 46, 141, 1, 64, 163, 78, 165, 144, 191, 56, 204, 132, 114, 58, 176,
+ 222, 164, 46, 209, 13, 197, 97, 6, 229, 242, 152, 9, 213, 116, 248,
+ 53, 20, 135, 25, 180, 187, 200, 56, 99, 241, 23, 27, 103, 208, 158,
+ 34, 227, 140, 95, 67, 177, 113, 6, 113, 66, 48, 19, 90, 7, 252,
+ 32, 208, 4, 51, 77, 217, 93, 81, 126, 192, 27, 83, 207, 28, 51,
+ 88, 142, 198, 128, 250, 220, 190, 145, 122, 226, 48, 131, 114, 105, 12,
+ 0, 26, 117, 42, 235, 197, 117, 197, 97, 198, 143, 211, 129, 245, 38,
+ 117, 9, 169, 43, 14, 51, 40, 151, 199, 140, 159, 166, 195, 85, 71,
+ 28, 102, 208, 238, 34, 227, 12, 218, 88, 100, 156, 9, 169, 43, 54,
+ 206, 160, 237, 68, 198, 25, 196, 9, 221, 107, 245, 28, 252, 160, 129,
+ 25, 102, 216, 158, 94, 87, 109, 104, 207, 107, 121, 176, 175, 160, 54,
+ 23, 3, 106, 115, 227, 25, 63, 129, 227, 25, 78, 135, 11, 222, 201,
+ 165, 233, 113, 248, 9, 28, 207, 212, 226, 234, 1, 52, 169, 75, 220,
+ 11, 129, 227, 153, 90, 185, 198, 51, 181, 180, 62, 230, 11, 129, 227,
+ 25, 63, 193, 227, 25, 63, 177, 113, 6, 237, 41, 50, 206, 216, 95,
+ 136, 141, 51, 136, 19, 138, 153, 199, 224, 7, 117, 242, 198, 204, 71,
+ 163, 70, 88, 38, 113, 223, 195, 14, 188, 206, 103, 238, 48, 163, 191,
+ 247, 6, 203, 209, 189, 131, 57, 76, 126, 204, 211, 188, 207, 211, 146,
+ 239, 183, 76, 250, 240, 120, 169, 96, 163, 92, 168, 155, 73, 195, 233,
+ 62, 25, 148, 75, 247, 14, 2, 141, 58, 21, 105, 217, 121, 235, 72,
+ 191, 87, 60, 97, 210, 238, 38, 134, 185, 80, 43, 39, 5, 177, 61,
+ 144, 156, 14, 172, 55, 169, 75, 232, 147, 188, 117, 188, 83, 229, 213,
+ 164, 184, 244, 118, 237, 141, 114, 161, 106, 206, 108, 65, 247, 226, 160,
+ 92, 221, 62, 120, 77, 135, 61, 43, 111, 29, 65, 83, 166, 218, 250,
+ 79, 118, 24, 230, 66, 53, 121, 155, 229, 66, 161, 221, 249, 252, 15,
+ 180, 35, 145, 71, 104, 204, 133, 98, 207, 45, 150, 101, 150, 122, 150,
+ 141, 150, 186, 150, 31, 225, 71, 218, 221, 115, 63, 151, 146, 253, 251,
+ 251, 210, 60, 32, 82, 30, 115, 161, 110, 204, 155, 97, 56, 39, 141,
+ 249, 31, 242, 154, 111, 104, 14, 140, 79, 191, 120, 154, 7, 244, 229,
+ 241, 36, 211, 28, 152, 11, 93, 78, 104, 101, 150, 80, 26, 243, 63,
+ 216, 243, 188, 99, 79, 154, 230, 23, 188, 13, 240, 59, 19, 27, 16,
+ 26, 115, 96, 216, 115, 180, 65, 32, 216, 32, 8, 108, 16, 164, 203,
+ 129, 201, 118, 244, 166, 249, 96, 164, 60, 230, 192, 188, 21, 93, 199,
+ 52, 31, 236, 207, 243, 133, 104, 62, 216, 167, 125, 175, 5, 19, 27,
+ 248, 239, 58, 18, 108, 102, 131, 202, 59, 214, 5, 19, 27, 16, 26,
+ 109, 192, 158, 27, 219, 0, 253, 150, 183, 1, 250, 33, 177, 1, 161,
+ 49, 23, 138, 61, 71, 27, 84, 7, 27, 84, 7, 27, 84, 215, 229,
+ 66, 221, 27, 205, 114, 161, 72, 121, 204, 133, 234, 181, 185, 150, 105,
+ 46, 212, 238, 227, 251, 168, 31, 236, 217, 61, 134, 230, 66, 29, 154,
+ 81, 200, 212, 15, 214, 7, 236, 167, 185, 80, 132, 198, 92, 40, 246,
+ 220, 216, 6, 136, 43, 222, 6, 136, 19, 98, 3, 66, 163, 31, 176,
+ 231, 104, 131, 241, 96, 131, 241, 96, 131, 241, 58, 63, 8, 175, 199,
+ 114, 161, 72, 121, 244, 131, 105, 46, 243, 92, 168, 149, 119, 89, 46,
+ 84, 151, 217, 44, 23, 106, 180, 203, 60, 23, 106, 220, 58, 150, 11,
+ 69, 104, 244, 3, 246, 220, 100, 63, 230, 99, 46, 23, 234, 33, 180,
+ 107, 207, 13, 99, 128, 62, 23, 10, 120, 157, 153, 30, 196, 128, 199,
+ 92, 219, 249, 136, 203, 133, 202, 244, 52, 6, 184, 239, 11, 32, 222,
+ 105, 219, 249, 136, 139, 1, 64, 163, 78, 165, 223, 145, 225, 105, 12,
+ 112, 175, 3, 241, 68, 235, 193, 233, 192, 122, 147, 186, 132, 101, 120,
+ 26, 3, 220, 235, 64, 127, 165, 245, 200, 204, 21, 3, 136, 189, 50,
+ 60, 141, 1, 238, 117, 160, 63, 208, 190, 124, 166, 62, 55, 136, 181,
+ 155, 14, 27, 161, 49, 215, 200, 168, 61, 213, 229, 66, 101, 232, 229,
+ 177, 54, 200, 97, 35, 52, 230, 26, 25, 181, 77, 186, 92, 168, 92,
+ 242, 24, 158, 29, 54, 66, 227, 251, 25, 225, 92, 55, 127, 144, 75,
+ 30, 195, 134, 195, 70, 104, 124, 63, 35, 204, 232, 114, 161, 30, 114,
+ 243, 192, 119, 192, 15, 30, 155, 97, 134, 203, 133, 2, 94, 191, 251,
+ 230, 152, 193, 114, 52, 135, 40, 157, 155, 7, 190, 39, 14, 51, 40,
+ 151, 142, 157, 225, 157, 80, 167, 226, 115, 247, 196, 97, 6, 229, 210,
+ 57, 0, 160, 73, 93, 82, 238, 138, 195, 140, 223, 253, 92, 243, 192,
+ 247, 181, 190, 217, 93, 113, 152, 65, 187, 243, 125, 111, 119, 152, 193,
+ 190, 183, 167, 152, 177, 231, 146, 231, 14, 51, 40, 207, 83, 204, 160,
+ 61, 121, 121, 238, 48, 131, 99, 13, 79, 49, 19, 154, 75, 158, 59,
+ 204, 224, 251, 121, 138, 25, 196, 9, 157, 7, 190, 9, 126, 240, 208,
+ 12, 51, 44, 23, 42, 20, 120, 93, 183, 205, 49, 131, 229, 232, 216,
+ 249, 63, 110, 30, 248, 182, 56, 204, 160, 92, 58, 118, 6, 26, 117,
+ 42, 133, 110, 139, 195, 76, 40, 167, 3, 235, 77, 234, 18, 125, 75,
+ 28, 102, 80, 174, 110, 30, 88, 211, 225, 119, 75, 28, 102, 208, 238,
+ 249, 197, 12, 63, 103, 100, 185, 157, 127, 204, 240, 242, 208, 158, 249,
+ 197, 12, 47, 207, 239, 86, 254, 49, 195, 247, 205, 16, 39, 116, 30,
+ 248, 42, 248, 193, 29, 51, 204, 176, 92, 25, 63, 224, 141, 185, 110,
+ 142, 25, 44, 71, 99, 192, 13, 110, 30, 248, 122, 254, 48, 195, 143,
+ 207, 81, 46, 141, 1, 64, 163, 78, 101, 30, 248, 90, 254, 48, 195,
+ 143, 207, 253, 56, 29, 88, 111, 82, 151, 144, 107, 249, 195, 12, 63,
+ 62, 71, 185, 186, 121, 96, 77, 135, 235, 106, 254, 48, 67, 198, 231,
+ 193, 154, 221, 137, 15, 133, 132, 22, 113, 230, 92, 144, 95, 26, 159,
+ 251, 57, 79, 216, 174, 254, 55, 54, 207, 241, 185, 46, 167, 245, 154,
+ 62, 87, 198, 59, 180, 206, 203, 99, 93, 144, 23, 213, 169, 113, 158,
+ 99, 93, 221, 249, 252, 156, 188, 155, 35, 139, 56, 135, 128, 13, 115,
+ 143, 27, 157, 7, 78, 216, 74, 103, 54, 207, 115, 220, 168, 235, 59,
+ 94, 213, 231, 202, 216, 54, 204, 120, 121, 12, 6, 239, 247, 100, 86,
+ 222, 99, 48, 62, 206, 32, 78, 104, 223, 236, 18, 248, 193, 77, 51,
+ 204, 176, 92, 25, 215, 21, 104, 207, 47, 155, 99, 6, 203, 209, 24,
+ 112, 133, 203, 149, 57, 239, 41, 102, 220, 231, 127, 212, 157, 220, 155,
+ 222, 77, 30, 202, 233, 112, 193, 59, 185, 52, 61, 49, 169, 158, 98,
+ 198, 189, 142, 192, 14, 61, 169, 14, 148, 75, 235, 1, 52, 169, 139,
+ 235, 180, 167, 152, 113, 175, 99, 221, 26, 150, 43, 19, 122, 57, 215,
+ 60, 240, 101, 173, 111, 118, 212, 83, 204, 184, 215, 17, 203, 231, 202,
+ 156, 103, 123, 12, 151, 250, 7, 57, 209, 142, 68, 30, 161, 59, 199,
+ 205, 177, 179, 231, 228, 76, 232, 134, 150, 182, 240, 35, 237, 174, 171,
+ 215, 51, 251, 124, 248, 70, 100, 143, 225, 125, 123, 15, 165, 124, 175,
+ 212, 65, 210, 168, 169, 13, 232, 156, 111, 95, 139, 191, 101, 4, 240,
+ 205, 228, 120, 31, 149, 95, 42, 49, 172, 198, 210, 249, 51, 239, 103,
+ 155, 37, 35, 172, 146, 61, 134, 78, 199, 96, 186, 39, 255, 203, 240,
+ 97, 10, 141, 185, 50, 97, 51, 70, 82, 222, 56, 224, 221, 14, 124,
+ 59, 57, 222, 231, 5, 246, 73, 31, 72, 147, 233, 222, 223, 119, 142,
+ 206, 86, 104, 204, 149, 217, 18, 56, 143, 242, 38, 2, 79, 50, 252,
+ 14, 232, 120, 79, 73, 31, 255, 180, 56, 145, 236, 49, 44, 49, 97,
+ 89, 34, 217, 99, 120, 252, 207, 21, 148, 247, 48, 240, 28, 183, 212,
+ 177, 164, 192, 143, 223, 99, 88, 117, 216, 218, 68, 178, 199, 240, 114,
+ 179, 53, 10, 93, 44, 226, 178, 244, 173, 229, 43, 202, 123, 18, 120,
+ 78, 195, 47, 149, 227, 125, 18, 121, 77, 250, 126, 242, 162, 68, 178,
+ 199, 112, 198, 115, 245, 142, 202, 130, 17, 183, 165, 55, 231, 71, 25,
+ 246, 5, 106, 68, 221, 149, 134, 7, 76, 79, 36, 123, 12, 23, 182,
+ 90, 160, 208, 99, 34, 210, 165, 152, 179, 95, 80, 222, 11, 240, 206,
+ 151, 224, 119, 133, 211, 27, 29, 149, 41, 101, 13, 254, 37, 145, 236,
+ 49, 188, 90, 251, 188, 66, 143, 138, 200, 150, 126, 207, 178, 208, 246,
+ 234, 154, 165, 182, 229, 134, 165, 150, 229, 150, 165, 38, 229, 221, 235,
+ 200, 145, 18, 151, 208, 253, 178, 242, 76, 167, 85, 161, 107, 219, 188,
+ 228, 38, 105, 108, 47, 236, 29, 104, 227, 238, 193, 47, 141, 155, 35,
+ 75, 119, 122, 203, 151, 127, 171, 146, 68, 246, 24, 30, 252, 182, 148,
+ 66, 159, 11, 47, 44, 23, 204, 184, 77, 223, 57, 221, 82, 195, 146,
+ 1, 58, 179, 44, 126, 148, 247, 66, 100, 49, 57, 61, 115, 23, 221,
+ 251, 219, 214, 246, 181, 118, 183, 103, 41, 185, 217, 176, 37, 148, 55,
+ 7, 222, 217, 203, 171, 142, 165, 144, 23, 251, 190, 89, 206, 210, 114,
+ 221, 148, 40, 186, 39, 255, 213, 10, 170, 221, 158, 183, 47, 43, 47,
+ 94, 56, 198, 116, 79, 62, 155, 3, 246, 165, 52, 238, 49, 228, 231,
+ 134, 139, 131, 190, 210, 240, 43, 199, 233, 165, 123, 242, 83, 25, 46,
+ 63, 3, 92, 98, 219, 67, 215, 63, 52, 186, 35, 224, 146, 61, 119,
+ 143, 203, 51, 128, 203, 18, 247, 139, 211, 28, 182, 176, 58, 93, 149,
+ 242, 109, 1, 151, 143, 222, 188, 210, 150, 225, 178, 161, 134, 75, 127,
+ 93, 174, 12, 139, 121, 177, 116, 78, 183, 16, 224, 210, 40, 230, 17,
+ 92, 254, 147, 89, 141, 230, 176, 157, 223, 238, 163, 157, 217, 149, 32,
+ 93, 152, 88, 168, 29, 195, 101, 32, 224, 50, 16, 112, 25, 168, 219,
+ 251, 187, 176, 254, 173, 96, 130, 203, 164, 222, 169, 193, 100, 239, 111,
+ 214, 172, 223, 131, 25, 46, 3, 1, 151, 1, 128, 203, 0, 150, 75,
+ 86, 240, 148, 52, 41, 253, 16, 205, 149, 217, 243, 223, 230, 96, 21,
+ 31, 103, 165, 110, 55, 215, 6, 51, 92, 6, 0, 46, 3, 0, 151,
+ 140, 55, 27, 112, 121, 123, 237, 176, 96, 130, 203, 6, 173, 135, 42,
+ 116, 97, 192, 229, 144, 63, 7, 7, 51, 92, 250, 3, 46, 3, 0,
+ 151, 140, 215, 18, 117, 77, 186, 242, 252, 11, 186, 39, 127, 103, 240,
+ 214, 96, 178, 247, 119, 221, 140, 131, 134, 125, 234, 39, 145, 119, 165,
+ 147, 235, 238, 7, 19, 92, 174, 222, 148, 173, 210, 128, 203, 245, 255,
+ 120, 183, 99, 184, 12, 4, 92, 6, 2, 46, 3, 185, 182, 36, 83,
+ 122, 45, 248, 81, 48, 193, 165, 163, 210, 35, 77, 47, 224, 50, 61,
+ 51, 152, 225, 50, 16, 112, 25, 8, 184, 12, 228, 222, 57, 71, 58,
+ 246, 40, 139, 148, 145, 35, 239, 168, 186, 188, 1, 151, 27, 222, 47,
+ 214, 142, 225, 50, 16, 112, 25, 8, 184, 12, 212, 229, 202, 172, 186,
+ 84, 149, 238, 201, 239, 151, 229, 167, 229, 36, 21, 150, 183, 215, 99,
+ 185, 15, 233, 192, 147, 1, 191, 44, 206, 55, 48, 87, 230, 208, 63,
+ 129, 52, 135, 109, 171, 83, 245, 37, 47, 91, 41, 185, 86, 11, 107,
+ 59, 134, 75, 224, 241, 10, 2, 92, 6, 113, 216, 42, 45, 159, 40,
+ 220, 156, 230, 176, 213, 89, 216, 76, 227, 45, 43, 79, 45, 213, 204,
+ 52, 135, 141, 173, 75, 248, 82, 26, 113, 201, 175, 87, 20, 7, 125,
+ 165, 225, 87, 142, 211, 75, 247, 228, 159, 102, 184, 252, 4, 112, 137,
+ 241, 154, 224, 146, 208, 203, 0, 151, 236, 57, 226, 210, 31, 144, 229,
+ 15, 184, 100, 216, 234, 219, 251, 153, 253, 69, 171, 186, 52, 87, 166,
+ 242, 212, 195, 106, 249, 179, 131, 164, 110, 210, 21, 46, 94, 6, 2,
+ 46, 253, 1, 151, 13, 88, 110, 85, 185, 165, 18, 235, 59, 198, 210,
+ 117, 134, 247, 0, 151, 70, 125, 71, 228, 237, 93, 112, 155, 180, 100,
+ 99, 85, 154, 43, 83, 230, 31, 245, 252, 133, 190, 128, 203, 121, 101,
+ 254, 229, 226, 101, 13, 192, 101, 77, 192, 101, 45, 93, 174, 76, 219,
+ 23, 203, 105, 188, 244, 122, 212, 73, 161, 111, 61, 61, 42, 69, 94,
+ 222, 151, 192, 112, 89, 7, 112, 89, 15, 112, 201, 222, 185, 46, 224,
+ 114, 201, 183, 111, 180, 33, 184, 236, 216, 241, 148, 226, 119, 37, 0,
+ 151, 175, 93, 173, 222, 142, 225, 210, 95, 195, 37, 243, 181, 173, 128,
+ 75, 185, 237, 92, 154, 43, 19, 116, 98, 154, 154, 211, 58, 251, 178,
+ 52, 185, 206, 168, 118, 12, 151, 141, 0, 151, 141, 0, 151, 236, 187,
+ 29, 135, 120, 89, 229, 206, 247, 20, 151, 101, 47, 87, 81, 231, 64,
+ 195, 111, 75, 51, 55, 71, 24, 238, 223, 40, 2, 241, 242, 210, 249,
+ 102, 52, 94, 62, 190, 175, 174, 171, 148, 138, 76, 151, 106, 173, 252,
+ 57, 129, 225, 178, 30, 224, 178, 62, 224, 146, 213, 247, 52, 196, 203,
+ 26, 35, 75, 210, 92, 153, 97, 99, 212, 92, 153, 111, 195, 179, 165,
+ 154, 219, 92, 237, 244, 184, 108, 12, 184, 180, 82, 222, 25, 17, 57,
+ 210, 153, 45, 52, 39, 70, 174, 217, 183, 181, 66, 31, 4, 92, 102,
+ 62, 108, 215, 158, 225, 178, 37, 224, 178, 37, 224, 178, 21, 229, 109,
+ 150, 236, 45, 23, 155, 80, 156, 230, 150, 134, 222, 254, 167, 157, 218,
+ 183, 40, 44, 7, 28, 123, 157, 195, 101, 51, 192, 165, 85, 135, 203,
+ 121, 128, 203, 94, 242, 185, 4, 130, 203, 160, 173, 235, 149, 250, 238,
+ 128, 120, 121, 102, 94, 42, 23, 47, 235, 107, 241, 146, 197, 248, 79,
+ 1, 151, 233, 29, 74, 208, 92, 153, 7, 73, 170, 143, 37, 64, 188,
+ 44, 221, 52, 192, 120, 45, 11, 112, 201, 214, 202, 124, 41, 141, 185,
+ 50, 252, 26, 90, 113, 175, 234, 128, 203, 234, 128, 203, 234, 47, 231,
+ 150, 30, 213, 231, 202, 196, 114, 185, 50, 177, 92, 174, 76, 44, 151,
+ 43, 163, 198, 203, 9, 128, 203, 9, 186, 92, 25, 236, 63, 19, 92,
+ 254, 194, 229, 202, 36, 149, 99, 188, 125, 129, 103, 4, 252, 102, 90,
+ 194, 116, 185, 50, 108, 12, 22, 75, 215, 190, 48, 94, 26, 141, 193,
+ 72, 188, 188, 247, 53, 203, 149, 121, 222, 49, 220, 70, 226, 101, 233,
+ 59, 44, 31, 34, 14, 244, 109, 135, 223, 78, 78, 47, 198, 203, 173,
+ 71, 89, 174, 204, 232, 234, 179, 105, 174, 76, 195, 49, 236, 157, 19,
+ 129, 39, 25, 126, 7, 56, 94, 204, 149, 201, 28, 200, 114, 101, 62,
+ 106, 58, 155, 230, 202, 52, 173, 202, 120, 15, 3, 207, 113, 248, 165,
+ 112, 188, 216, 143, 237, 177, 147, 229, 202, 188, 157, 204, 114, 101, 134,
+ 29, 102, 243, 52, 39, 129, 231, 52, 252, 82, 117, 188, 215, 164, 215,
+ 187, 205, 166, 185, 50, 227, 7, 207, 166, 185, 50, 43, 167, 207, 54,
+ 205, 149, 185, 251, 238, 108, 154, 43, 243, 79, 128, 74, 23, 134, 120,
+ 121, 224, 9, 211, 123, 1, 244, 93, 130, 223, 21, 78, 111, 57, 192,
+ 229, 39, 37, 103, 211, 92, 153, 105, 90, 174, 73, 13, 136, 151, 61,
+ 63, 100, 103, 184, 92, 3, 158, 27, 240, 187, 197, 241, 158, 142, 204,
+ 145, 166, 87, 154, 70, 115, 101, 182, 30, 156, 170, 174, 85, 2, 46,
+ 175, 79, 158, 106, 99, 184, 28, 7, 184, 28, 7, 184, 28, 199, 245,
+ 39, 189, 229, 123, 103, 89, 174, 204, 131, 127, 85, 127, 120, 12, 253,
+ 216, 203, 215, 217, 247, 77, 7, 159, 200, 128, 95, 22, 167, 247, 25,
+ 224, 114, 242, 167, 44, 87, 230, 104, 51, 109, 157, 19, 226, 229, 84,
+ 46, 39, 41, 7, 121, 188, 194, 0, 151, 97, 186, 92, 153, 57, 167,
+ 89, 174, 204, 199, 111, 178, 92, 153, 5, 127, 153, 231, 202, 176, 245,
+ 91, 95, 74, 99, 188, 228, 215, 117, 139, 123, 141, 7, 92, 142, 7,
+ 92, 142, 127, 121, 15, 243, 37, 46, 87, 230, 36, 140, 147, 175, 154,
+ 205, 41, 112, 185, 50, 192, 27, 122, 218, 131, 185, 235, 75, 220, 120,
+ 223, 197, 237, 45, 59, 37, 112, 238, 218, 197, 141, 247, 129, 70, 157,
+ 138, 180, 83, 2, 231, 174, 121, 29, 80, 111, 82, 23, 159, 83, 226,
+ 230, 174, 81, 174, 110, 238, 90, 211, 17, 115, 82, 220, 220, 53, 218,
+ 93, 228, 122, 143, 227, 148, 216, 245, 30, 159, 83, 98, 215, 123, 208,
+ 118, 34, 215, 123, 16, 39, 116, 189, 231, 16, 248, 193, 37, 51, 204,
+ 112, 185, 50, 127, 66, 249, 195, 230, 152, 193, 114, 20, 51, 71, 184,
+ 245, 158, 195, 2, 49, 115, 132, 243, 103, 160, 81, 167, 26, 76, 4,
+ 98, 134, 211, 129, 245, 38, 117, 137, 254, 67, 224, 122, 207, 225, 92,
+ 152, 209, 116, 248, 253, 33, 112, 189, 231, 176, 224, 245, 158, 195, 130,
+ 215, 123, 254, 16, 188, 222, 243, 135, 224, 245, 158, 67, 220, 122, 207,
+ 254, 12, 111, 191, 147, 102, 152, 97, 185, 50, 126, 192, 27, 115, 208,
+ 131, 245, 158, 67, 220, 58, 201, 239, 220, 122, 207, 65, 113, 152, 65,
+ 185, 116, 189, 7, 104, 212, 169, 174, 11, 136, 195, 140, 31, 167, 3,
+ 235, 77, 234, 18, 114, 64, 28, 102, 80, 174, 110, 189, 71, 211, 225,
+ 218, 47, 14, 51, 104, 119, 145, 113, 6, 109, 44, 50, 206, 132, 28,
+ 16, 27, 103, 208, 118, 34, 227, 12, 226, 132, 198, 153, 61, 224, 7,
+ 135, 76, 48, 195, 229, 202, 184, 246, 65, 31, 104, 175, 7, 235, 61,
+ 251, 184, 24, 176, 143, 235, 155, 37, 139, 195, 76, 40, 167, 195, 5,
+ 239, 228, 210, 244, 56, 146, 197, 97, 6, 229, 210, 122, 0, 77, 234,
+ 226, 147, 44, 176, 111, 182, 55, 215, 122, 207, 94, 173, 111, 230, 20,
+ 216, 55, 75, 22, 27, 103, 28, 201, 98, 227, 140, 79, 178, 216, 56,
+ 131, 182, 19, 26, 103, 246, 112, 113, 102, 55, 248, 193, 126, 51, 204,
+ 176, 61, 159, 126, 136, 177, 68, 15, 226, 204, 30, 174, 125, 78, 226,
+ 226, 76, 162, 192, 56, 147, 196, 197, 25, 160, 81, 167, 18, 103, 18,
+ 4, 198, 25, 78, 7, 214, 155, 212, 37, 36, 65, 96, 156, 73, 204,
+ 21, 103, 52, 29, 174, 221, 2, 227, 76, 162, 224, 56, 147, 32, 56,
+ 206, 36, 8, 142, 51, 187, 5, 199, 153, 221, 28, 102, 182, 131, 31,
+ 236, 113, 135, 153, 145, 227, 63, 26, 52, 77, 217, 35, 109, 225, 219,
+ 192, 93, 128, 177, 223, 60, 200, 47, 219, 197, 181, 207, 187, 152, 124,
+ 251, 206, 252, 221, 27, 84, 179, 91, 249, 166, 180, 125, 230, 116, 184,
+ 224, 157, 92, 154, 30, 191, 95, 243, 119, 111, 144, 37, 118, 94, 60,
+ 173, 199, 111, 92, 61, 128, 166, 117, 249, 37, 127, 247, 6, 253, 52,
+ 124, 49, 59, 183, 246, 183, 92, 113, 230, 55, 13, 51, 219, 243, 119,
+ 111, 208, 225, 38, 83, 104, 174, 12, 218, 93, 151, 35, 1, 118, 164,
+ 123, 93, 52, 250, 163, 150, 11, 36, 246, 220, 125, 187, 235, 106, 80,
+ 85, 46, 111, 209, 46, 211, 195, 28, 9, 173, 124, 225, 172, 55, 229,
+ 90, 239, 148, 50, 228, 205, 46, 50, 88, 182, 219, 30, 169, 23, 65,
+ 90, 198, 200, 13, 106, 252, 165, 208, 197, 50, 102, 200, 145, 119, 190,
+ 183, 26, 241, 62, 157, 247, 177, 60, 123, 152, 151, 149, 228, 7, 16,
+ 218, 255, 220, 10, 238, 185, 113, 142, 4, 250, 5, 111, 3, 252, 206,
+ 212, 166, 26, 141, 54, 96, 207, 243, 182, 65, 153, 175, 99, 226, 137,
+ 13, 72, 121, 180, 193, 225, 14, 142, 120, 51, 27, 244, 248, 104, 96,
+ 60, 177, 193, 142, 174, 114, 60, 177, 65, 159, 165, 21, 227, 205, 108,
+ 208, 227, 204, 135, 63, 19, 27, 16, 26, 109, 192, 158, 27, 219, 0,
+ 253, 150, 183, 1, 250, 33, 177, 1, 161, 187, 128, 13, 216, 115, 247,
+ 242, 194, 192, 6, 103, 127, 141, 165, 185, 50, 164, 252, 43, 96, 131,
+ 179, 9, 31, 27, 242, 22, 47, 58, 88, 238, 251, 219, 135, 73, 196,
+ 6, 253, 170, 116, 87, 104, 63, 176, 193, 222, 134, 53, 12, 121, 159,
+ 131, 13, 42, 253, 52, 133, 230, 76, 17, 26, 109, 192, 158, 27, 219,
+ 0, 113, 197, 219, 0, 113, 66, 108, 64, 232, 241, 96, 3, 246, 220,
+ 189, 188, 179, 96, 131, 162, 145, 31, 209, 92, 25, 82, 190, 40, 216,
+ 160, 255, 29, 99, 222, 39, 224, 7, 227, 35, 72, 158, 205, 24, 185,
+ 196, 5, 117, 46, 26, 253, 32, 243, 246, 44, 155, 153, 31, 20, 91,
+ 48, 155, 230, 202, 16, 26, 109, 192, 158, 27, 247, 155, 176, 221, 167,
+ 119, 183, 174, 133, 118, 109, 183, 81, 12, 208, 223, 93, 232, 218, 6,
+ 229, 227, 61, 136, 1, 219, 184, 182, 115, 27, 55, 214, 248, 57, 127,
+ 57, 198, 136, 119, 218, 118, 114, 58, 92, 240, 78, 46, 77, 79, 220,
+ 55, 249, 203, 49, 70, 60, 209, 122, 196, 115, 245, 0, 154, 212, 197,
+ 254, 77, 254, 114, 140, 209, 95, 105, 61, 226, 115, 197, 128, 120, 45,
+ 183, 96, 109, 254, 114, 140, 209, 31, 232, 88, 227, 103, 125, 238, 8,
+ 107, 55, 29, 54, 66, 207, 107, 159, 96, 55, 106, 79, 117, 57, 193,
+ 223, 232, 229, 177, 54, 200, 97, 35, 52, 202, 51, 106, 155, 116, 121,
+ 4, 185, 228, 49, 60, 59, 108, 132, 158, 11, 242, 140, 112, 174, 203,
+ 35, 88, 171, 151, 199, 176, 225, 176, 17, 26, 223, 207, 8, 51, 186,
+ 251, 102, 215, 114, 247, 45, 126, 5, 126, 176, 221, 8, 51, 205, 117,
+ 152, 73, 249, 58, 195, 59, 100, 141, 57, 102, 176, 28, 189, 111, 246,
+ 107, 38, 223, 181, 90, 28, 102, 66, 56, 29, 41, 240, 78, 41, 154,
+ 158, 176, 213, 226, 48, 131, 114, 105, 61, 128, 166, 117, 89, 45, 14,
+ 51, 33, 107, 244, 152, 65, 157, 202, 92, 243, 87, 226, 48, 131, 118,
+ 39, 62, 20, 99, 111, 226, 22, 51, 209, 241, 91, 60, 198, 76, 88,
+ 46, 121, 238, 48, 131, 242, 60, 197, 140, 133, 147, 23, 10, 242, 220,
+ 97, 6, 229, 121, 138, 25, 180, 29, 255, 126, 238, 48, 131, 242, 60,
+ 197, 12, 226, 132, 96, 38, 229, 11, 240, 131, 181, 70, 152, 105, 161,
+ 195, 76, 244, 42, 224, 253, 210, 28, 51, 88, 142, 248, 129, 207, 42,
+ 46, 47, 127, 165, 56, 204, 248, 112, 58, 162, 225, 157, 162, 53, 61,
+ 214, 149, 226, 48, 131, 114, 105, 61, 128, 38, 117, 113, 174, 16, 135,
+ 25, 159, 47, 245, 152, 65, 157, 202, 28, 192, 10, 113, 152, 65, 187,
+ 231, 23, 51, 252, 156, 145, 117, 101, 254, 49, 195, 203, 67, 123, 230,
+ 23, 51, 188, 188, 144, 21, 249, 199, 12, 223, 55, 67, 156, 16, 204,
+ 68, 127, 6, 244, 87, 70, 152, 105, 169, 195, 76, 8, 240, 166, 44,
+ 51, 199, 12, 150, 163, 49, 96, 57, 183, 239, 127, 89, 254, 48, 195,
+ 143, 207, 81, 46, 141, 1, 64, 163, 78, 165, 255, 247, 121, 254, 48,
+ 195, 143, 207, 67, 56, 29, 88, 111, 82, 23, 199, 231, 249, 195, 12,
+ 63, 62, 71, 185, 186, 187, 211, 53, 29, 62, 159, 231, 15, 51, 100,
+ 124, 30, 172, 217, 157, 191, 27, 58, 232, 113, 177, 151, 198, 231, 97,
+ 97, 19, 237, 157, 227, 170, 53, 245, 164, 29, 71, 27, 243, 242, 190,
+ 29, 243, 238, 75, 99, 93, 148, 247, 107, 139, 213, 241, 30, 173, 249,
+ 115, 242, 222, 24, 81, 196, 217, 109, 251, 232, 151, 198, 141, 149, 199,
+ 79, 180, 251, 253, 28, 227, 209, 189, 50, 62, 156, 188, 56, 120, 191,
+ 218, 221, 167, 189, 52, 6, 155, 6, 239, 55, 179, 203, 36, 143, 226,
+ 140, 130, 19, 50, 127, 186, 17, 252, 224, 11, 35, 204, 180, 210, 97,
+ 38, 230, 167, 12, 111, 191, 173, 30, 156, 103, 249, 19, 55, 71, 251,
+ 19, 147, 239, 216, 236, 41, 102, 10, 187, 247, 103, 126, 174, 153, 211,
+ 17, 3, 239, 20, 163, 233, 113, 109, 242, 20, 51, 230, 58, 80, 46,
+ 173, 7, 208, 164, 46, 246, 31, 60, 197, 140, 7, 245, 216, 154, 43,
+ 143, 121, 171, 182, 118, 178, 209, 83, 204, 228, 165, 195, 161, 96, 102,
+ 164, 151, 106, 247, 122, 74, 73, 117, 143, 97, 46, 121, 22, 178, 199,
+ 80, 199, 93, 178, 190, 165, 153, 69, 253, 145, 118, 215, 217, 235, 153,
+ 189, 208, 159, 73, 141, 201, 30, 195, 41, 213, 212, 184, 228, 151, 58,
+ 72, 58, 242, 222, 135, 134, 49, 42, 173, 252, 82, 41, 32, 131, 96,
+ 53, 150, 206, 159, 149, 30, 151, 36, 61, 141, 175, 102, 56, 31, 150,
+ 254, 217, 63, 146, 227, 83, 167, 149, 236, 155, 203, 185, 125, 74, 161,
+ 11, 205, 120, 44, 205, 26, 120, 214, 80, 239, 115, 217, 34, 255, 85,
+ 171, 72, 83, 178, 127, 237, 102, 195, 210, 77, 213, 61, 134, 69, 229,
+ 77, 243, 43, 25, 234, 205, 41, 80, 70, 102, 243, 124, 190, 148, 14,
+ 187, 81, 69, 54, 155, 255, 35, 182, 71, 127, 20, 101, 251, 223, 19,
+ 223, 137, 35, 182, 63, 212, 83, 141, 225, 104, 251, 50, 143, 143, 255,
+ 108, 102, 251, 9, 211, 73, 187, 22, 75, 231, 237, 208, 246, 15, 27,
+ 175, 142, 55, 179, 125, 212, 234, 228, 120, 98, 251, 1, 125, 23, 197,
+ 19, 219, 47, 159, 242, 81, 188, 153, 237, 235, 22, 255, 229, 103, 98,
+ 251, 128, 38, 235, 127, 38, 182, 191, 176, 99, 254, 207, 102, 182, 103,
+ 243, 139, 190, 148, 70, 219, 155, 205, 59, 18, 219, 35, 78, 137, 237,
+ 83, 243, 176, 253, 103, 30, 216, 222, 187, 207, 51, 251, 221, 224, 15,
+ 104, 46, 74, 82, 45, 181, 191, 243, 243, 63, 131, 164, 55, 6, 158,
+ 53, 236, 251, 84, 2, 219, 151, 218, 53, 154, 238, 121, 39, 49, 224,
+ 202, 216, 36, 233, 147, 173, 49, 134, 115, 120, 49, 203, 254, 145, 46,
+ 94, 221, 150, 68, 108, 127, 240, 96, 180, 66, 247, 154, 249, 88, 106,
+ 84, 102, 158, 33, 111, 115, 176, 253, 103, 71, 253, 105, 254, 209, 16,
+ 91, 29, 133, 14, 7, 219, 7, 204, 173, 106, 200, 123, 31, 108, 207,
+ 230, 53, 125, 41, 221, 21, 108, 111, 54, 223, 73, 108, 143, 237, 151,
+ 222, 239, 29, 54, 102, 123, 149, 238, 160, 216, 222, 97, 211, 219, 254,
+ 154, 206, 246, 199, 193, 239, 215, 45, 99, 251, 154, 63, 215, 250, 134,
+ 77, 192, 239, 47, 255, 103, 124, 222, 250, 109, 176, 125, 66, 183, 105,
+ 116, 95, 51, 137, 151, 101, 192, 239, 255, 54, 136, 151, 200, 91, 244,
+ 243, 127, 164, 140, 152, 9, 116, 175, 238, 176, 79, 39, 43, 116, 69,
+ 240, 251, 54, 231, 77, 206, 151, 7, 219, 63, 34, 251, 85, 193, 246,
+ 127, 253, 166, 210, 197, 192, 246, 22, 155, 241, 59, 63, 3, 219, 179,
+ 249, 84, 95, 74, 143, 3, 219, 155, 205, 179, 210, 125, 120, 27, 185,
+ 57, 203, 111, 97, 12, 246, 153, 81, 140, 111, 173, 143, 241, 27, 32,
+ 206, 125, 239, 65, 140, 223, 192, 197, 198, 13, 76, 190, 223, 103, 226,
+ 198, 146, 126, 156, 142, 24, 120, 167, 24, 77, 79, 220, 119, 226, 198,
+ 146, 40, 151, 214, 3, 104, 82, 23, 251, 119, 226, 198, 146, 126, 223,
+ 231, 138, 241, 223, 107, 115, 150, 223, 138, 27, 75, 162, 221, 69, 206,
+ 191, 160, 141, 69, 206, 191, 216, 191, 19, 59, 255, 130, 182, 19, 57,
+ 255, 130, 56, 161, 231, 34, 46, 1, 63, 216, 104, 132, 153, 215, 244,
+ 115, 150, 235, 97, 204, 182, 206, 131, 57, 203, 245, 220, 56, 111, 61,
+ 55, 103, 25, 35, 112, 206, 146, 211, 145, 2, 239, 148, 162, 233, 9,
+ 139, 17, 56, 103, 185, 142, 171, 7, 208, 164, 46, 113, 75, 5, 206,
+ 89, 174, 203, 53, 103, 185, 78, 195, 229, 82, 129, 115, 150, 49, 98,
+ 231, 95, 194, 98, 196, 206, 191, 160, 61, 69, 206, 191, 216, 151, 138,
+ 157, 127, 65, 156, 208, 115, 228, 22, 130, 31, 124, 107, 128, 153, 166,
+ 86, 29, 102, 236, 192, 235, 92, 108, 142, 25, 44, 71, 207, 95, 251,
+ 148, 59, 71, 110, 113, 254, 48, 115, 234, 226, 56, 138, 25, 148, 75,
+ 207, 145, 3, 26, 117, 42, 184, 92, 148, 63, 204, 248, 237, 77, 165,
+ 152, 177, 115, 58, 176, 222, 164, 46, 97, 139, 242, 135, 153, 161, 241,
+ 87, 216, 121, 120, 139, 115, 157, 35, 71, 236, 181, 40, 127, 152, 249,
+ 121, 20, 119, 142, 220, 98, 230, 67, 185, 229, 161, 77, 115, 247, 175,
+ 77, 247, 236, 44, 202, 91, 30, 218, 239, 127, 42, 47, 204, 64, 30,
+ 218, 234, 127, 42, 207, 98, 32, 15, 237, 226, 169, 60, 122, 142, 220,
+ 66, 134, 25, 251, 199, 224, 7, 75, 140, 48, 163, 223, 83, 100, 1,
+ 94, 199, 39, 230, 152, 193, 114, 244, 28, 185, 5, 76, 190, 207, 39,
+ 226, 226, 12, 202, 165, 190, 134, 58, 22, 106, 243, 22, 243, 197, 197,
+ 25, 11, 167, 3, 235, 77, 234, 98, 157, 47, 46, 206, 160, 92, 30,
+ 51, 22, 77, 135, 243, 99, 113, 113, 6, 237, 46, 50, 206, 160, 141,
+ 69, 198, 25, 235, 124, 177, 113, 6, 109, 39, 50, 206, 32, 78, 8,
+ 102, 44, 81, 224, 7, 11, 141, 48, 163, 223, 131, 225, 156, 7, 237,
+ 249, 92, 115, 204, 96, 57, 26, 3, 230, 49, 249, 41, 115, 196, 97,
+ 198, 206, 233, 112, 194, 59, 57, 53, 61, 161, 115, 196, 97, 6, 229,
+ 210, 122, 0, 77, 234, 146, 22, 37, 14, 51, 246, 185, 122, 204, 160,
+ 78, 69, 90, 148, 56, 204, 160, 221, 69, 142, 103, 66, 231, 136, 29,
+ 207, 160, 61, 69, 142, 103, 28, 81, 98, 199, 51, 136, 19, 58, 207,
+ 255, 97, 166, 183, 253, 99, 119, 152, 25, 53, 120, 212, 32, 188, 26,
+ 97, 146, 238, 140, 95, 71, 36, 140, 127, 198, 103, 190, 244, 45, 115,
+ 99, 6, 203, 17, 63, 136, 179, 112, 229, 199, 101, 122, 91, 76, 254,
+ 140, 246, 174, 182, 238, 48, 141, 222, 91, 128, 114, 233, 28, 0, 188,
+ 19, 234, 84, 250, 102, 99, 60, 209, 145, 247, 222, 213, 237, 91, 199,
+ 178, 59, 75, 198, 51, 29, 88, 111, 82, 23, 231, 104, 79, 116, 228,
+ 189, 119, 117, 218, 233, 222, 108, 14, 128, 211, 97, 209, 116, 42, 255,
+ 126, 232, 137, 142, 188, 247, 174, 158, 110, 62, 155, 238, 93, 69, 187,
+ 243, 251, 245, 208, 142, 196, 135, 8, 141, 103, 91, 179, 231, 238, 219,
+ 93, 60, 219, 186, 94, 121, 114, 46, 70, 119, 153, 148, 199, 179, 173,
+ 183, 180, 124, 203, 144, 247, 113, 137, 177, 242, 215, 191, 221, 214, 238,
+ 114, 157, 37, 175, 158, 234, 183, 75, 157, 243, 141, 146, 171, 85, 155,
+ 210, 214, 120, 206, 119, 129, 188, 187, 223, 112, 122, 198, 57, 161, 241,
+ 108, 107, 246, 220, 100, 207, 226, 24, 189, 13, 240, 59, 19, 27, 16,
+ 26, 109, 192, 158, 187, 151, 151, 10, 54, 200, 241, 157, 74, 207, 121,
+ 39, 229, 139, 129, 13, 154, 141, 29, 109, 122, 206, 123, 244, 180, 161,
+ 244, 156, 247, 13, 97, 31, 180, 35, 54, 8, 29, 253, 78, 59, 51,
+ 27, 164, 150, 238, 211, 142, 216, 128, 208, 104, 3, 246, 220, 216, 6,
+ 232, 183, 188, 13, 208, 15, 137, 13, 8, 141, 54, 96, 207, 243, 182,
+ 193, 199, 139, 122, 209, 243, 254, 73, 121, 180, 193, 185, 208, 62, 166,
+ 231, 253, 255, 214, 189, 63, 61, 231, 189, 64, 207, 62, 244, 188, 255,
+ 133, 79, 122, 154, 158, 243, 30, 90, 211, 78, 247, 174, 18, 26, 109,
+ 192, 158, 27, 219, 0, 113, 197, 219, 0, 113, 66, 108, 64, 104, 180,
+ 1, 123, 158, 183, 13, 170, 52, 152, 77, 247, 174, 146, 242, 104, 131,
+ 203, 173, 102, 155, 158, 243, 94, 214, 62, 155, 158, 243, 254, 203, 27,
+ 179, 233, 57, 239, 211, 123, 206, 54, 61, 231, 189, 196, 187, 108, 239,
+ 42, 161, 209, 6, 236, 185, 201, 60, 48, 216, 128, 158, 139, 56, 12,
+ 218, 153, 40, 179, 24, 192, 206, 172, 142, 25, 149, 233, 237, 55, 210,
+ 60, 6, 96, 57, 218, 118, 142, 98, 229, 227, 70, 120, 26, 3, 220,
+ 247, 5, 16, 239, 180, 237, 228, 116, 196, 192, 59, 197, 104, 122, 236,
+ 35, 60, 141, 1, 238, 117, 32, 158, 104, 61, 70, 114, 245, 0, 154,
+ 212, 37, 101, 184, 167, 49, 192, 189, 14, 244, 87, 90, 143, 145, 185,
+ 98, 128, 102, 223, 208, 225, 158, 198, 0, 247, 58, 208, 31, 232, 156,
+ 209, 136, 76, 221, 94, 78, 214, 110, 58, 108, 132, 198, 115, 207, 141,
+ 218, 83, 221, 188, 109, 46, 121, 172, 13, 114, 216, 8, 141, 242, 140,
+ 218, 38, 221, 188, 237, 112, 189, 60, 134, 103, 135, 141, 208, 40, 207,
+ 8, 231, 186, 126, 93, 46, 121, 12, 27, 14, 27, 161, 81, 158, 17,
+ 102, 116, 103, 86, 15, 99, 152, 137, 25, 4, 126, 192, 197, 103, 247,
+ 152, 225, 206, 172, 6, 94, 215, 16, 115, 204, 96, 57, 186, 23, 123,
+ 40, 43, 31, 54, 68, 28, 102, 80, 46, 221, 139, 13, 52, 234, 84,
+ 10, 13, 17, 135, 153, 80, 78, 7, 214, 155, 212, 37, 122, 176, 56,
+ 204, 160, 92, 221, 25, 6, 154, 14, 191, 193, 226, 48, 131, 118, 231,
+ 243, 198, 220, 97, 6, 243, 198, 60, 197, 140, 37, 151, 60, 119, 152,
+ 65, 121, 158, 98, 6, 237, 201, 203, 115, 135, 25, 148, 231, 41, 102,
+ 252, 114, 201, 115, 135, 25, 148, 231, 41, 102, 16, 39, 116, 189, 49,
+ 28, 252, 96, 152, 25, 102, 184, 51, 171, 17, 99, 179, 205, 49, 131,
+ 229, 104, 12, 8, 101, 229, 173, 161, 226, 48, 131, 114, 169, 14, 120,
+ 39, 212, 169, 196, 178, 8, 129, 113, 102, 54, 23, 103, 128, 38, 117,
+ 177, 71, 8, 140, 51, 179, 115, 197, 25, 205, 190, 41, 225, 226, 48,
+ 131, 118, 207, 47, 102, 116, 107, 29, 17, 249, 199, 140, 110, 173, 35,
+ 34, 255, 152, 225, 229, 161, 237, 242, 139, 25, 190, 111, 134, 56, 161,
+ 57, 18, 211, 193, 15, 6, 153, 97, 134, 157, 89, 157, 50, 43, 211,
+ 59, 100, 166, 57, 102, 176, 28, 93, 167, 155, 197, 202, 187, 102, 228,
+ 15, 51, 252, 248, 60, 132, 211, 145, 2, 239, 148, 162, 233, 9, 155,
+ 145, 63, 204, 240, 227, 115, 148, 75, 235, 1, 52, 173, 203, 140, 252,
+ 97, 134, 31, 159, 135, 204, 212, 99, 38, 69, 179, 111, 244, 244, 252,
+ 97, 134, 140, 207, 131, 53, 187, 19, 31, 114, 189, 91, 196, 249, 113,
+ 133, 243, 193, 185, 199, 231, 209, 71, 78, 216, 206, 22, 76, 246, 232,
+ 174, 193, 48, 78, 222, 161, 247, 139, 56, 39, 166, 110, 9, 206, 61,
+ 214, 117, 130, 188, 166, 119, 231, 121, 118, 231, 46, 39, 239, 13, 144,
+ 183, 123, 111, 159, 132, 220, 227, 198, 80, 144, 119, 183, 243, 4, 207,
+ 114, 36, 166, 51, 121, 150, 129, 69, 156, 127, 111, 140, 122, 105, 12,
+ 22, 119, 244, 132, 237, 92, 118, 184, 103, 57, 18, 211, 25, 102, 82,
+ 154, 131, 31, 132, 155, 97, 166, 21, 219, 191, 63, 13, 120, 167, 154,
+ 99, 6, 203, 209, 220, 130, 105, 172, 188, 223, 68, 79, 49, 227, 227,
+ 222, 159, 75, 183, 221, 77, 115, 11, 56, 29, 209, 240, 78, 209, 154,
+ 30, 107, 176, 167, 152, 113, 175, 99, 218, 241, 177, 109, 104, 61, 166,
+ 114, 245, 0, 154, 212, 197, 222, 218, 83, 204, 184, 215, 177, 166, 252,
+ 25, 122, 150, 188, 207, 84, 61, 102, 162, 53, 251, 134, 180, 240, 20,
+ 51, 238, 117, 124, 243, 66, 197, 140, 179, 128, 106, 247, 122, 74, 73,
+ 117, 31, 25, 218, 145, 250, 184, 70, 227, 254, 73, 246, 220, 125, 187,
+ 139, 251, 39, 251, 37, 52, 218, 77, 246, 145, 125, 147, 220, 85, 161,
+ 131, 82, 7, 73, 15, 14, 142, 48, 228, 245, 241, 93, 42, 157, 10,
+ 250, 178, 45, 217, 71, 70, 176, 90, 241, 217, 102, 105, 245, 103, 107,
+ 12, 231, 195, 202, 23, 220, 38, 245, 61, 119, 71, 43, 179, 83, 138,
+ 125, 165, 182, 130, 157, 170, 207, 18, 164, 230, 39, 122, 24, 198, 158,
+ 199, 5, 246, 73, 63, 237, 88, 76, 207, 173, 45, 211, 105, 131, 66,
+ 63, 13, 63, 44, 69, 151, 220, 102, 200, 155, 25, 121, 76, 114, 30,
+ 76, 214, 202, 164, 72, 63, 120, 29, 209, 120, 79, 74, 253, 131, 79,
+ 27, 242, 62, 143, 60, 35, 21, 105, 126, 142, 158, 17, 63, 49, 240,
+ 178, 122, 71, 95, 196, 89, 233, 108, 157, 91, 198, 239, 28, 121, 65,
+ 122, 107, 98, 6, 61, 35, 126, 219, 219, 143, 180, 243, 229, 47, 75,
+ 37, 236, 89, 198, 243, 62, 145, 215, 164, 240, 185, 247, 233, 25, 241,
+ 69, 134, 164, 41, 116, 199, 136, 219, 82, 172, 244, 192, 144, 183, 223,
+ 156, 187, 82, 224, 205, 235, 244, 204, 219, 218, 209, 69, 149, 125, 138,
+ 127, 58, 210, 165, 247, 79, 188, 98, 184, 103, 241, 189, 168, 76, 41,
+ 116, 127, 127, 173, 76, 150, 116, 244, 122, 132, 66, 219, 194, 179, 165,
+ 249, 94, 203, 12, 121, 227, 34, 114, 164, 236, 10, 241, 244, 140, 248,
+ 242, 245, 118, 40, 244, 215, 54, 47, 57, 166, 233, 78, 67, 222, 198,
+ 201, 222, 242, 170, 175, 99, 232, 30, 77, 223, 178, 170, 174, 202, 17,
+ 133, 229, 55, 174, 143, 55, 228, 221, 22, 89, 76, 238, 191, 180, 161,
+ 86, 166, 164, 124, 225, 7, 245, 187, 252, 209, 190, 148, 188, 229, 249,
+ 14, 67, 91, 173, 112, 150, 150, 75, 180, 28, 79, 207, 136, 63, 215,
+ 163, 137, 66, 239, 110, 95, 86, 14, 40, 127, 209, 208, 159, 241, 204,
+ 91, 54, 127, 236, 75, 105, 60, 243, 214, 108, 94, 153, 96, 26, 219,
+ 57, 130, 105, 188, 187, 1, 219, 45, 26, 103, 52, 26, 239, 110, 96,
+ 207, 221, 203, 251, 23, 48, 157, 250, 93, 17, 186, 47, 119, 210, 218,
+ 113, 74, 249, 158, 128, 233, 15, 166, 215, 51, 236, 119, 102, 149, 95,
+ 42, 249, 238, 111, 74, 207, 136, 39, 241, 18, 239, 110, 24, 183, 105,
+ 186, 241, 121, 220, 5, 182, 73, 213, 215, 134, 211, 51, 226, 51, 143,
+ 168, 103, 60, 23, 6, 76, 95, 58, 180, 208, 144, 247, 25, 96, 122,
+ 254, 196, 21, 237, 8, 166, 255, 170, 181, 86, 61, 7, 60, 226, 176,
+ 148, 147, 181, 174, 157, 49, 46, 143, 73, 71, 131, 55, 180, 35, 152,
+ 62, 19, 242, 131, 198, 123, 82, 186, 48, 116, 179, 241, 59, 3, 166,
+ 119, 63, 220, 218, 142, 96, 250, 131, 121, 241, 234, 156, 52, 96, 186,
+ 96, 165, 95, 12, 121, 45, 81, 23, 164, 111, 198, 236, 166, 231, 88,
+ 63, 206, 114, 170, 231, 233, 3, 166, 223, 157, 119, 208, 144, 183, 64,
+ 212, 53, 105, 137, 245, 120, 59, 130, 233, 117, 209, 127, 41, 180, 15,
+ 96, 250, 113, 218, 191, 134, 188, 205, 162, 238, 74, 143, 222, 188, 209,
+ 142, 96, 122, 231, 195, 108, 133, 238, 31, 145, 46, 253, 211, 181, 72,
+ 123, 35, 222, 14, 128, 233, 228, 130, 85, 219, 19, 76, 223, 172, 22,
+ 216, 94, 197, 86, 182, 228, 104, 25, 108, 200, 219, 52, 50, 71, 106,
+ 191, 234, 3, 122, 142, 245, 227, 153, 3, 21, 186, 55, 98, 250, 131,
+ 80, 67, 222, 7, 78, 111, 185, 113, 41, 59, 61, 199, 122, 149, 203,
+ 170, 208, 127, 132, 23, 150, 39, 46, 42, 103, 200, 123, 6, 48, 189,
+ 251, 226, 45, 122, 190, 188, 207, 171, 170, 157, 31, 0, 166, 43, 12,
+ 251, 177, 157, 177, 222, 210, 242, 149, 239, 86, 208, 243, 229, 223, 148,
+ 23, 41, 116, 22, 96, 186, 77, 242, 108, 99, 191, 2, 76, 179, 245,
+ 16, 95, 74, 95, 0, 76, 155, 173, 147, 16, 76, 99, 191, 130, 96,
+ 26, 239, 125, 192, 126, 2, 193, 52, 161, 241, 222, 7, 246, 220, 189,
+ 188, 211, 128, 233, 107, 79, 147, 219, 18, 76, 119, 45, 122, 85, 41,
+ 223, 30, 48, 253, 161, 165, 170, 97, 251, 242, 0, 48, 253, 211, 23,
+ 101, 232, 125, 44, 164, 207, 90, 16, 48, 29, 236, 59, 208, 176, 77,
+ 44, 0, 113, 186, 207, 175, 163, 232, 125, 44, 199, 146, 35, 212, 187,
+ 141, 1, 211, 29, 174, 47, 72, 52, 195, 116, 229, 217, 107, 105, 156,
+ 118, 90, 54, 171, 52, 96, 122, 73, 114, 188, 49, 47, 96, 218, 235,
+ 195, 93, 52, 78, 255, 60, 110, 143, 198, 123, 82, 122, 123, 226, 126,
+ 211, 56, 61, 213, 113, 136, 198, 233, 109, 27, 143, 210, 56, 125, 255,
+ 120, 138, 137, 222, 11, 82, 157, 15, 254, 166, 113, 250, 221, 5, 255,
+ 104, 188, 151, 165, 232, 237, 231, 18, 141, 219, 131, 107, 210, 188, 123,
+ 169, 52, 78, 127, 87, 92, 189, 83, 165, 1, 96, 58, 163, 254, 69,
+ 67, 222, 56, 192, 244, 152, 27, 231, 104, 156, 238, 80, 250, 169, 66,
+ 79, 159, 157, 46, 85, 108, 88, 202, 48, 230, 165, 0, 166, 223, 250,
+ 178, 57, 141, 211, 221, 218, 246, 85, 232, 154, 128, 233, 202, 183, 63,
+ 50, 228, 29, 48, 59, 71, 154, 57, 114, 37, 141, 211, 219, 63, 89,
+ 165, 208, 223, 3, 166, 247, 111, 92, 109, 200, 123, 21, 48, 189, 233,
+ 124, 20, 141, 211, 13, 215, 140, 83, 232, 197, 128, 233, 222, 227, 236,
+ 134, 188, 177, 128, 233, 173, 101, 202, 209, 56, 221, 166, 213, 37, 165,
+ 190, 23, 0, 211, 247, 254, 216, 99, 104, 171, 191, 1, 211, 201, 182,
+ 53, 52, 78, 71, 206, 81, 253, 240, 38, 96, 186, 226, 138, 177, 198,
+ 223, 23, 48, 205, 214, 247, 124, 41, 253, 47, 96, 218, 108, 221, 143,
+ 96, 26, 251, 241, 124, 223, 27, 251, 229, 4, 211, 132, 198, 190, 55,
+ 123, 158, 119, 223, 251, 251, 82, 44, 135, 99, 169, 86, 30, 115, 151,
+ 206, 92, 49, 230, 197, 220, 165, 115, 107, 103, 211, 28, 14, 50, 110,
+ 44, 0, 152, 30, 83, 195, 108, 13, 109, 155, 212, 172, 232, 108, 122,
+ 54, 253, 192, 125, 234, 126, 189, 130, 128, 233, 197, 17, 102, 247, 44,
+ 239, 147, 206, 209, 59, 154, 15, 73, 239, 204, 8, 215, 206, 121, 63,
+ 44, 173, 178, 27, 231, 112, 96, 156, 62, 127, 143, 228, 127, 164, 72,
+ 31, 238, 82, 105, 140, 211, 89, 243, 102, 217, 204, 48, 253, 221, 219,
+ 179, 232, 185, 246, 71, 26, 206, 162, 231, 218, 167, 63, 158, 105, 194,
+ 123, 65, 218, 176, 113, 38, 61, 215, 222, 54, 127, 166, 141, 96, 58,
+ 117, 184, 25, 239, 53, 233, 234, 132, 153, 244, 92, 251, 175, 123, 105,
+ 247, 89, 3, 166, 223, 106, 100, 204, 235, 15, 152, 126, 176, 121, 38,
+ 205, 149, 249, 226, 152, 122, 94, 79, 56, 196, 233, 196, 187, 83, 13,
+ 121, 147, 0, 211, 187, 119, 77, 164, 231, 218, 55, 254, 104, 156, 66,
+ 47, 7, 76, 159, 174, 63, 202, 144, 119, 136, 35, 71, 90, 178, 252,
+ 61, 122, 174, 125, 171, 148, 119, 213, 92, 25, 192, 116, 149, 146, 239,
+ 26, 242, 158, 0, 76, 23, 93, 54, 140, 230, 232, 92, 136, 87, 117,
+ 45, 1, 76, 31, 188, 63, 193, 248, 157, 1, 211, 157, 202, 78, 163,
+ 231, 218, 63, 94, 171, 214, 61, 29, 48, 189, 100, 152, 177, 111, 100,
+ 3, 166, 43, 84, 141, 160, 231, 218, 39, 173, 140, 160, 231, 218, 15,
+ 171, 48, 219, 244, 92, 123, 182, 94, 237, 75, 105, 60, 215, 222, 108,
+ 29, 155, 230, 204, 55, 103, 115, 40, 214, 129, 64, 79, 55, 155, 67,
+ 97, 103, 116, 135, 0, 111, 74, 83, 243, 57, 20, 44, 71, 231, 4,
+ 155, 177, 242, 161, 77, 197, 205, 213, 163, 92, 58, 39, 8, 52, 234,
+ 84, 188, 207, 42, 110, 174, 62, 132, 211, 129, 245, 38, 117, 113, 88,
+ 197, 205, 213, 163, 92, 93, 206, 188, 166, 35, 110, 160, 184, 185, 122,
+ 180, 187, 200, 245, 45, 180, 177, 200, 245, 45, 135, 85, 236, 250, 22,
+ 218, 78, 228, 250, 150, 130, 19, 77, 94, 218, 59, 224, 7, 205, 205,
+ 48, 195, 206, 232, 142, 251, 32, 211, 219, 250, 190, 57, 102, 176, 28,
+ 241, 3, 235, 7, 172, 188, 243, 61, 113, 152, 177, 114, 58, 226, 224,
+ 157, 226, 52, 61, 33, 239, 137, 195, 12, 202, 165, 245, 0, 154, 212,
+ 197, 245, 174, 56, 204, 88, 223, 215, 99, 38, 78, 179, 111, 216, 187,
+ 226, 48, 131, 118, 23, 185, 190, 21, 242, 158, 216, 245, 45, 180, 167,
+ 200, 245, 173, 176, 119, 197, 174, 111, 33, 78, 8, 102, 226, 222, 2,
+ 63, 24, 104, 130, 25, 238, 140, 238, 48, 224, 77, 27, 96, 142, 25,
+ 44, 71, 252, 32, 237, 109, 86, 222, 49, 64, 28, 102, 80, 46, 209,
+ 17, 6, 52, 234, 84, 34, 247, 0, 113, 152, 9, 227, 116, 96, 189,
+ 73, 93, 98, 250, 139, 195, 12, 202, 229, 49, 19, 166, 233, 176, 246,
+ 23, 135, 25, 180, 187, 200, 56, 227, 51, 64, 108, 156, 65, 123, 138,
+ 140, 51, 214, 254, 98, 227, 12, 226, 132, 96, 38, 172, 15, 248, 193,
+ 59, 102, 152, 97, 123, 182, 173, 192, 27, 215, 207, 28, 51, 88, 142,
+ 198, 128, 55, 89, 121, 123, 63, 113, 152, 65, 185, 52, 6, 0, 141,
+ 58, 149, 145, 80, 95, 113, 152, 177, 114, 58, 176, 222, 164, 46, 161,
+ 125, 197, 97, 6, 229, 242, 152, 177, 106, 58, 210, 250, 136, 195, 12,
+ 218, 93, 100, 156, 65, 27, 139, 140, 51, 161, 125, 197, 198, 25, 180,
+ 157, 200, 56, 131, 56, 161, 103, 116, 119, 7, 63, 120, 203, 12, 51,
+ 108, 143, 107, 90, 239, 76, 239, 152, 158, 230, 152, 193, 114, 116, 95,
+ 80, 47, 110, 239, 81, 79, 129, 123, 143, 122, 113, 251, 130, 128, 70,
+ 157, 74, 255, 175, 135, 56, 204, 248, 113, 58, 176, 222, 164, 46, 33,
+ 61, 196, 97, 6, 229, 234, 206, 181, 215, 116, 184, 186, 11, 220, 123,
+ 212, 83, 108, 156, 65, 27, 139, 140, 51, 33, 61, 196, 198, 25, 180,
+ 157, 200, 56, 131, 56, 161, 152, 233, 4, 125, 154, 62, 121, 98, 230,
+ 163, 81, 35, 70, 106, 50, 180, 89, 165, 110, 153, 222, 161, 93, 73,
+ 121, 95, 25, 111, 170, 192, 140, 165, 151, 238, 79, 233, 198, 237, 63,
+ 237, 198, 197, 153, 46, 153, 121, 222, 111, 240, 101, 74, 243, 221, 181,
+ 188, 146, 218, 27, 229, 6, 37, 255, 23, 201, 238, 208, 226, 116, 184,
+ 224, 157, 92, 154, 30, 191, 55, 242, 214, 113, 124, 70, 221, 36, 203,
+ 148, 27, 109, 141, 114, 131, 78, 245, 237, 206, 246, 159, 118, 229, 234,
+ 1, 52, 173, 203, 235, 121, 235, 240, 143, 94, 148, 20, 245, 209, 174,
+ 182, 70, 185, 65, 203, 198, 244, 98, 103, 26, 119, 213, 99, 198, 165,
+ 217, 215, 213, 41, 111, 29, 255, 38, 15, 180, 253, 94, 194, 97, 120,
+ 174, 125, 70, 111, 150, 27, 132, 118, 231, 243, 33, 208, 142, 68, 30,
+ 161, 49, 31, 130, 61, 199, 251, 62, 155, 88, 54, 90, 172, 150, 31,
+ 185, 59, 94, 49, 55, 168, 236, 152, 63, 180, 50, 221, 101, 82, 30,
+ 115, 131, 198, 207, 27, 100, 24, 163, 48, 55, 168, 85, 220, 11, 109,
+ 109, 103, 150, 156, 54, 110, 109, 27, 117, 46, 55, 74, 206, 184, 18,
+ 178, 219, 120, 62, 118, 129, 124, 239, 249, 251, 218, 250, 207, 18, 74,
+ 99, 62, 4, 123, 158, 119, 236, 73, 211, 252, 130, 183, 1, 126, 103,
+ 98, 3, 66, 163, 13, 216, 115, 180, 65, 16, 216, 32, 16, 108, 16,
+ 168, 203, 9, 73, 123, 240, 38, 205, 139, 33, 229, 49, 39, 228, 191,
+ 130, 93, 77, 243, 98, 130, 47, 203, 52, 47, 230, 217, 158, 96, 154,
+ 23, 211, 224, 135, 214, 166, 121, 49, 137, 205, 173, 52, 47, 134, 208,
+ 104, 3, 246, 220, 216, 6, 232, 183, 188, 13, 208, 15, 137, 13, 8,
+ 141, 54, 96, 207, 209, 6, 141, 220, 218, 224, 148, 181, 59, 181, 1,
+ 41, 143, 54, 8, 110, 30, 98, 106, 131, 39, 23, 222, 164, 54, 216,
+ 48, 180, 55, 181, 65, 213, 81, 230, 185, 65, 67, 130, 88, 110, 16,
+ 161, 209, 6, 236, 185, 177, 13, 16, 87, 188, 13, 16, 39, 196, 6,
+ 132, 70, 27, 176, 231, 104, 131, 105, 96, 131, 105, 96, 131, 105, 58,
+ 27, 124, 215, 153, 229, 6, 145, 242, 104, 131, 31, 251, 153, 231, 6,
+ 29, 121, 143, 229, 6, 45, 30, 202, 114, 131, 126, 29, 101, 158, 27,
+ 84, 118, 50, 203, 13, 34, 52, 218, 128, 61, 55, 238, 55, 97, 187,
+ 79, 243, 67, 37, 104, 215, 186, 27, 198, 0, 93, 126, 168, 171, 35,
+ 148, 239, 224, 65, 12, 232, 200, 181, 157, 29, 153, 252, 52, 217, 211,
+ 24, 224, 190, 47, 128, 120, 167, 109, 39, 167, 195, 5, 239, 228, 210,
+ 244, 56, 100, 79, 99, 128, 123, 29, 136, 39, 90, 143, 14, 92, 61,
+ 128, 38, 117, 241, 145, 61, 141, 1, 238, 117, 160, 191, 210, 122, 116,
+ 200, 21, 3, 52, 251, 198, 72, 158, 198, 0, 247, 58, 208, 31, 104,
+ 223, 91, 214, 231, 202, 176, 118, 211, 97, 35, 52, 230, 202, 24, 181,
+ 167, 186, 121, 219, 92, 242, 88, 27, 228, 176, 17, 26, 229, 25, 181,
+ 77, 186, 241, 126, 46, 121, 12, 207, 14, 27, 161, 81, 158, 17, 206,
+ 117, 227, 125, 73, 47, 143, 97, 195, 97, 35, 52, 202, 51, 194, 140,
+ 238, 126, 83, 137, 235, 55, 5, 129, 31, 116, 50, 195, 12, 151, 79,
+ 103, 135, 254, 118, 99, 115, 204, 96, 57, 218, 71, 111, 194, 141, 53,
+ 26, 139, 195, 12, 202, 165, 99, 13, 160, 81, 167, 50, 214, 104, 36,
+ 14, 51, 126, 156, 14, 172, 55, 169, 75, 72, 35, 113, 152, 65, 185,
+ 186, 177, 134, 166, 195, 21, 36, 14, 51, 104, 119, 190, 239, 237, 14,
+ 51, 216, 247, 246, 20, 51, 104, 99, 94, 158, 59, 204, 160, 60, 79,
+ 49, 19, 146, 75, 158, 59, 204, 160, 60, 79, 49, 131, 182, 227, 229,
+ 185, 195, 12, 202, 243, 20, 51, 136, 19, 26, 103, 26, 102, 122, 251,
+ 73, 102, 152, 97, 249, 116, 174, 64, 192, 88, 128, 7, 113, 38, 144,
+ 107, 159, 3, 185, 56, 227, 47, 48, 206, 112, 58, 92, 240, 78, 46,
+ 77, 143, 195, 95, 96, 156, 9, 224, 234, 1, 52, 169, 139, 143, 191,
+ 192, 56, 19, 144, 43, 206, 104, 246, 141, 105, 40, 48, 206, 248, 231,
+ 31, 51, 252, 156, 145, 195, 63, 255, 152, 225, 229, 249, 248, 231, 31,
+ 51, 188, 60, 180, 93, 126, 49, 195, 247, 205, 16, 39, 52, 111, 187,
+ 14, 248, 65, 144, 25, 102, 88, 62, 93, 76, 3, 192, 88, 125, 15,
+ 226, 76, 3, 46, 6, 52, 224, 242, 182, 235, 229, 15, 51, 252, 248,
+ 220, 143, 211, 17, 3, 239, 20, 163, 233, 177, 215, 203, 31, 102, 248,
+ 241, 57, 202, 165, 245, 0, 154, 212, 37, 165, 110, 254, 48, 195, 143,
+ 207, 253, 234, 231, 202, 167, 211, 236, 27, 90, 55, 127, 152, 33, 227,
+ 243, 96, 205, 238, 196, 135, 252, 222, 43, 226, 252, 44, 235, 104, 66,
+ 238, 241, 185, 227, 200, 9, 91, 192, 131, 253, 121, 142, 207, 117, 121,
+ 219, 156, 188, 79, 62, 40, 226, 28, 89, 249, 203, 132, 220, 99, 93,
+ 235, 209, 19, 182, 11, 47, 134, 229, 57, 214, 213, 229, 109, 215, 101,
+ 242, 124, 222, 47, 226, 76, 92, 243, 106, 66, 238, 113, 35, 230, 6,
+ 205, 223, 51, 62, 207, 113, 163, 46, 111, 155, 147, 87, 116, 96, 17,
+ 103, 203, 45, 81, 47, 141, 193, 156, 248, 126, 213, 35, 242, 28, 131,
+ 233, 242, 182, 235, 112, 125, 179, 90, 224, 7, 13, 205, 48, 195, 242,
+ 233, 66, 129, 215, 85, 203, 28, 51, 88, 142, 198, 128, 218, 92, 223,
+ 172, 186, 167, 152, 113, 159, 239, 210, 54, 180, 35, 187, 179, 189, 54,
+ 23, 3, 128, 70, 157, 10, 102, 42, 123, 138, 25, 247, 58, 2, 50,
+ 70, 209, 188, 157, 80, 78, 7, 214, 155, 212, 37, 196, 215, 83, 204,
+ 184, 215, 33, 117, 187, 64, 117, 160, 92, 93, 222, 182, 166, 195, 90,
+ 210, 83, 204, 184, 215, 177, 130, 203, 13, 66, 187, 243, 251, 19, 209,
+ 142, 68, 30, 161, 113, 127, 34, 123, 142, 103, 76, 55, 177, 52, 4,
+ 220, 180, 133, 31, 191, 63, 113, 76, 199, 202, 116, 207, 241, 134, 226,
+ 29, 20, 58, 48, 117, 144, 116, 43, 101, 44, 229, 237, 11, 60, 35,
+ 224, 55, 147, 227, 45, 229, 187, 84, 74, 76, 107, 181, 155, 236, 79,
+ 36, 88, 45, 255, 108, 179, 84, 98, 102, 140, 225, 92, 90, 185, 130,
+ 219, 164, 87, 187, 223, 10, 38, 251, 19, 187, 246, 171, 161, 204, 47,
+ 87, 121, 150, 32, 93, 45, 240, 6, 157, 107, 142, 179, 52, 181, 108,
+ 183, 52, 179, 236, 180, 52, 103, 249, 61, 5, 246, 73, 187, 253, 23,
+ 208, 60, 130, 173, 239, 169, 185, 3, 152, 27, 148, 49, 121, 11, 229,
+ 77, 180, 180, 176, 36, 91, 90, 90, 14, 88, 90, 177, 185, 135, 200,
+ 99, 210, 188, 51, 187, 104, 30, 193, 145, 142, 251, 20, 250, 89, 248,
+ 73, 233, 234, 182, 35, 38, 185, 0, 103, 164, 17, 11, 254, 164, 121,
+ 4, 183, 127, 73, 165, 121, 4, 19, 175, 94, 164, 188, 135, 65, 223,
+ 113, 203, 171, 150, 20, 248, 49, 189, 23, 164, 249, 235, 238, 208, 60,
+ 130, 155, 245, 210, 84, 58, 226, 178, 212, 118, 211, 67, 202, 123, 18,
+ 120, 78, 91, 90, 91, 254, 178, 180, 166, 188, 94, 81, 215, 164, 83,
+ 115, 238, 210, 60, 130, 168, 87, 31, 40, 116, 175, 136, 219, 210, 198,
+ 255, 50, 40, 111, 42, 240, 158, 5, 190, 243, 28, 239, 71, 115, 238,
+ 74, 242, 226, 251, 52, 143, 224, 82, 139, 210, 202, 62, 252, 139, 142,
+ 116, 41, 250, 112, 93, 186, 39, 255, 34, 240, 92, 178, 188, 102, 185,
+ 2, 222, 65, 120, 135, 69, 101, 74, 239, 47, 31, 72, 243, 8, 190,
+ 191, 52, 71, 161, 131, 195, 179, 165, 170, 143, 86, 82, 222, 107, 22,
+ 155, 229, 134, 69, 182, 220, 178, 116, 162, 188, 225, 17, 57, 82, 102,
+ 253, 157, 52, 143, 96, 111, 249, 221, 10, 253, 139, 205, 75, 174, 241,
+ 60, 145, 242, 222, 177, 116, 177, 220, 179, 116, 181, 164, 193, 143, 238,
+ 169, 76, 246, 150, 35, 46, 125, 71, 243, 8, 70, 39, 173, 80, 232,
+ 130, 17, 133, 229, 43, 55, 39, 81, 222, 116, 203, 235, 150, 12, 208,
+ 153, 101, 177, 83, 222, 31, 35, 139, 201, 19, 195, 131, 218, 147, 253,
+ 137, 27, 250, 169, 117, 63, 216, 190, 148, 108, 251, 124, 23, 181, 85,
+ 14, 214, 211, 171, 181, 165, 144, 87, 11, 202, 251, 185, 179, 180, 188,
+ 168, 196, 20, 154, 71, 112, 57, 165, 133, 66, 255, 214, 190, 172, 60,
+ 99, 202, 13, 195, 249, 93, 204, 13, 98, 243, 199, 190, 148, 190, 60,
+ 189, 130, 204, 207, 43, 23, 247, 178, 90, 74, 195, 175, 156, 151, 245,
+ 229, 60, 130, 202, 250, 60, 2, 108, 183, 8, 166, 9, 221, 9, 48,
+ 205, 158, 35, 166, 45, 47, 97, 250, 111, 192, 244, 206, 177, 55, 40,
+ 166, 23, 140, 89, 174, 230, 32, 0, 166, 103, 159, 172, 156, 192, 48,
+ 109, 213, 48, 221, 152, 205, 83, 151, 95, 42, 189, 114, 182, 62, 205,
+ 35, 32, 241, 18, 115, 131, 62, 59, 217, 215, 112, 110, 24, 247, 28,
+ 87, 28, 217, 147, 230, 17, 188, 255, 102, 31, 45, 7, 33, 65, 250,
+ 94, 126, 43, 145, 97, 58, 16, 48, 29, 8, 152, 14, 212, 237, 57,
+ 62, 241, 247, 32, 154, 71, 112, 252, 226, 72, 109, 79, 254, 97, 233,
+ 216, 144, 49, 137, 12, 211, 129, 128, 233, 64, 192, 116, 160, 110, 207,
+ 113, 141, 197, 97, 44, 223, 111, 247, 71, 26, 239, 73, 169, 249, 127,
+ 147, 76, 243, 8, 254, 120, 103, 50, 205, 35, 176, 125, 53, 85, 203,
+ 217, 59, 43, 237, 248, 103, 122, 34, 195, 116, 32, 96, 58, 16, 48,
+ 29, 168, 219, 115, 60, 175, 231, 108, 154, 71, 16, 248, 174, 131, 230,
+ 251, 149, 47, 19, 153, 200, 48, 29, 0, 152, 14, 0, 76, 7, 112,
+ 57, 73, 215, 164, 114, 21, 34, 104, 30, 193, 183, 61, 212, 242, 37,
+ 0, 211, 7, 163, 231, 36, 50, 76, 7, 0, 166, 3, 0, 211, 140,
+ 183, 86, 212, 93, 105, 224, 190, 121, 52, 143, 96, 115, 208, 114, 133,
+ 238, 18, 145, 46, 13, 252, 114, 125, 34, 195, 116, 0, 96, 58, 0,
+ 48, 237, 79, 121, 95, 7, 76, 59, 187, 144, 220, 200, 44, 41, 241,
+ 194, 69, 45, 127, 33, 91, 122, 54, 229, 121, 34, 195, 116, 67, 192,
+ 116, 3, 192, 52, 187, 143, 224, 245, 200, 28, 201, 175, 91, 77, 154,
+ 71, 48, 224, 114, 45, 133, 110, 8, 152, 174, 51, 189, 110, 18, 195,
+ 116, 93, 192, 116, 29, 192, 116, 29, 202, 155, 225, 244, 150, 171, 188,
+ 82, 130, 230, 17, 60, 173, 103, 81, 232, 127, 195, 11, 203, 159, 76,
+ 100, 57, 153, 233, 150, 122, 128, 233, 250, 128, 233, 6, 148, 247, 6,
+ 96, 186, 247, 48, 45, 175, 4, 48, 61, 187, 248, 103, 10, 253, 4,
+ 48, 125, 255, 125, 102, 171, 28, 172, 167, 87, 0, 96, 154, 125, 163,
+ 39, 128, 233, 253, 187, 198, 210, 60, 130, 140, 117, 161, 10, 253, 28,
+ 48, 253, 201, 130, 190, 134, 190, 129, 123, 142, 217, 122, 136, 47, 165,
+ 113, 207, 49, 191, 78, 82, 28, 244, 149, 134, 95, 57, 78, 47, 205,
+ 35, 240, 213, 99, 26, 251, 9, 4, 211, 132, 198, 220, 32, 246, 220,
+ 61, 166, 79, 1, 166, 255, 25, 180, 139, 98, 250, 251, 132, 107, 74,
+ 249, 118, 128, 233, 41, 49, 21, 19, 94, 142, 211, 12, 211, 25, 128,
+ 233, 244, 223, 139, 82, 76, 147, 62, 107, 33, 192, 244, 252, 79, 223,
+ 55, 92, 235, 40, 8, 113, 250, 175, 133, 163, 41, 166, 99, 219, 68,
+ 210, 220, 160, 98, 113, 139, 115, 97, 58, 0, 48, 29, 160, 203, 13,
+ 122, 163, 216, 122, 138, 233, 251, 177, 113, 52, 55, 40, 49, 235, 87,
+ 14, 211, 254, 128, 105, 127, 192, 116, 67, 93, 110, 208, 95, 139, 156,
+ 20, 211, 255, 245, 59, 72, 115, 131, 30, 189, 114, 212, 20, 211, 243,
+ 154, 254, 73, 49, 125, 165, 254, 95, 52, 55, 200, 94, 253, 28, 135,
+ 233, 134, 128, 233, 6, 128, 105, 230, 107, 79, 1, 211, 9, 21, 175,
+ 80, 76, 251, 84, 191, 70, 115, 131, 6, 213, 186, 193, 97, 186, 1,
+ 96, 186, 1, 96, 186, 129, 46, 55, 104, 181, 237, 50, 197, 244, 128,
+ 255, 174, 42, 244, 43, 128, 233, 230, 43, 111, 112, 152, 110, 0, 152,
+ 110, 0, 152, 102, 188, 147, 1, 211, 133, 182, 221, 160, 152, 222, 185,
+ 71, 197, 71, 58, 96, 186, 241, 22, 150, 27, 116, 17, 120, 46, 1,
+ 62, 174, 0, 78, 8, 111, 52, 96, 186, 122, 231, 32, 154, 27, 52,
+ 189, 64, 103, 245, 158, 101, 192, 116, 202, 239, 3, 147, 24, 166, 235,
+ 0, 166, 107, 1, 166, 107, 82, 222, 214, 142, 28, 233, 249, 150, 79,
+ 40, 166, 199, 215, 88, 168, 208, 145, 128, 233, 113, 75, 22, 113, 152,
+ 174, 14, 152, 174, 6, 152, 174, 70, 121, 239, 1, 166, 75, 198, 142,
+ 161, 152, 246, 31, 58, 64, 161, 183, 0, 166, 93, 87, 154, 36, 49,
+ 76, 215, 0, 76, 251, 1, 166, 89, 123, 176, 11, 48, 189, 186, 69,
+ 97, 154, 27, 84, 199, 91, 253, 94, 87, 1, 211, 19, 250, 109, 227,
+ 48, 13, 237, 143, 87, 67, 192, 52, 107, 195, 46, 2, 166, 11, 221,
+ 90, 70, 49, 29, 189, 64, 109, 3, 238, 1, 166, 195, 222, 30, 110,
+ 188, 134, 6, 152, 102, 235, 123, 190, 148, 198, 220, 32, 126, 221, 207,
+ 8, 211, 216, 143, 231, 251, 222, 43, 184, 220, 160, 21, 92, 110, 208,
+ 10, 46, 55, 72, 197, 244, 52, 192, 244, 52, 93, 223, 123, 95, 9,
+ 150, 27, 244, 25, 151, 27, 244, 245, 13, 198, 219, 23, 120, 70, 192,
+ 111, 38, 199, 139, 185, 65, 209, 63, 176, 220, 32, 50, 110, 196, 220,
+ 160, 113, 118, 227, 181, 59, 140, 211, 150, 166, 44, 55, 232, 155, 76,
+ 150, 27, 212, 126, 23, 27, 115, 198, 1, 207, 118, 248, 237, 212, 241,
+ 238, 147, 90, 182, 137, 160, 185, 65, 225, 167, 89, 110, 208, 186, 117,
+ 44, 255, 35, 209, 50, 21, 48, 61, 21, 48, 61, 85, 23, 167, 7,
+ 191, 29, 78, 115, 131, 126, 11, 12, 167, 185, 65, 62, 207, 205, 115,
+ 131, 86, 255, 195, 114, 131, 22, 110, 97, 185, 65, 211, 35, 25, 239,
+ 97, 208, 119, 28, 126, 41, 58, 189, 23, 164, 146, 77, 103, 209, 220,
+ 32, 159, 106, 179, 104, 110, 144, 111, 33, 198, 123, 18, 120, 78, 195,
+ 239, 47, 29, 239, 53, 41, 35, 96, 22, 205, 13, 74, 168, 160, 210,
+ 69, 1, 211, 115, 44, 140, 55, 21, 120, 206, 194, 239, 60, 199, 235,
+ 7, 152, 110, 62, 97, 22, 205, 13, 186, 113, 72, 189, 191, 123, 48,
+ 96, 186, 147, 223, 116, 27, 195, 244, 84, 192, 244, 84, 192, 244, 20,
+ 29, 166, 127, 24, 56, 153, 230, 6, 125, 149, 16, 166, 222, 57, 14,
+ 152, 142, 175, 52, 198, 198, 48, 61, 25, 48, 61, 9, 48, 253, 17,
+ 229, 221, 15, 152, 110, 90, 127, 16, 205, 13, 170, 57, 41, 84, 161,
+ 251, 0, 166, 95, 221, 59, 208, 198, 48, 61, 30, 48, 61, 30, 48,
+ 61, 158, 242, 158, 7, 76, 79, 79, 29, 73, 115, 131, 126, 30, 175,
+ 234, 218, 12, 152, 30, 184, 102, 162, 141, 97, 122, 2, 96, 250, 35,
+ 192, 244, 36, 202, 123, 12, 48, 189, 235, 149, 233, 52, 55, 232, 47,
+ 155, 90, 247, 76, 192, 244, 47, 41, 204, 55, 114, 176, 158, 94, 83,
+ 1, 211, 204, 175, 158, 2, 166, 207, 127, 200, 114, 131, 18, 206, 176,
+ 220, 160, 175, 236, 230, 185, 65, 108, 189, 218, 151, 210, 24, 167, 249,
+ 117, 236, 226, 160, 175, 52, 252, 202, 113, 122, 233, 92, 125, 45, 110,
+ 207, 118, 137, 76, 111, 87, 29, 179, 57, 148, 87, 217, 121, 57, 229,
+ 51, 189, 67, 202, 153, 207, 161, 96, 57, 154, 183, 83, 158, 59, 147,
+ 168, 172, 184, 185, 250, 16, 78, 71, 10, 188, 83, 138, 166, 39, 172,
+ 172, 184, 185, 122, 148, 75, 235, 1, 52, 173, 75, 89, 113, 115, 245,
+ 33, 229, 114, 157, 73, 164, 217, 55, 218, 71, 220, 92, 61, 218, 93,
+ 228, 250, 86, 88, 89, 177, 235, 91, 150, 178, 98, 215, 183, 208, 118,
+ 34, 215, 183, 16, 39, 116, 207, 118, 145, 76, 239, 208, 90, 102, 152,
+ 97, 249, 116, 86, 224, 141, 43, 102, 142, 25, 44, 71, 247, 58, 23,
+ 231, 246, 210, 21, 19, 135, 25, 148, 75, 247, 108, 3, 141, 58, 21,
+ 159, 43, 42, 14, 51, 86, 78, 7, 214, 155, 212, 37, 180, 168, 56,
+ 204, 160, 92, 221, 158, 109, 77, 71, 90, 17, 113, 152, 65, 187, 139,
+ 92, 223, 66, 27, 139, 92, 223, 10, 45, 42, 118, 125, 11, 109, 39,
+ 114, 125, 11, 113, 66, 115, 80, 11, 128, 31, 148, 48, 195, 12, 203,
+ 167, 75, 43, 156, 233, 29, 86, 200, 28, 51, 88, 142, 230, 237, 20,
+ 230, 190, 125, 33, 113, 152, 9, 227, 116, 164, 129, 220, 52, 77, 79,
+ 116, 65, 113, 152, 65, 185, 180, 30, 64, 147, 186, 248, 21, 20, 135,
+ 153, 176, 66, 122, 204, 164, 105, 54, 138, 43, 32, 14, 51, 104, 119,
+ 145, 113, 6, 109, 44, 50, 206, 248, 21, 20, 27, 103, 208, 118, 34,
+ 227, 12, 226, 132, 174, 111, 125, 10, 126, 80, 196, 4, 51, 92, 62,
+ 93, 156, 119, 166, 119, 204, 82, 115, 204, 96, 57, 26, 3, 188, 185,
+ 245, 173, 165, 226, 48, 99, 229, 116, 196, 121, 1, 246, 53, 61, 206,
+ 37, 226, 48, 131, 114, 233, 186, 51, 188, 59, 169, 75, 200, 18, 129,
+ 123, 143, 150, 230, 202, 65, 245, 210, 246, 30, 125, 42, 112, 239, 209,
+ 82, 177, 113, 6, 109, 44, 50, 206, 132, 44, 17, 27, 103, 208, 118,
+ 34, 227, 12, 226, 132, 238, 61, 90, 0, 126, 80, 192, 12, 51, 220,
+ 30, 215, 197, 208, 151, 91, 228, 193, 222, 163, 197, 220, 122, 237, 98,
+ 110, 239, 209, 66, 129, 123, 143, 56, 29, 46, 120, 39, 151, 166, 199,
+ 177, 80, 224, 222, 163, 69, 92, 61, 128, 38, 117, 241, 89, 40, 112,
+ 239, 209, 162, 92, 123, 143, 52, 251, 198, 44, 16, 184, 247, 104, 161,
+ 216, 56, 227, 88, 40, 54, 206, 248, 44, 20, 27, 103, 208, 118, 34,
+ 227, 12, 226, 132, 158, 229, 157, 3, 126, 240, 169, 27, 204, 76, 30,
+ 51, 142, 187, 54, 136, 237, 139, 249, 36, 211, 219, 111, 190, 7, 119,
+ 70, 124, 194, 237, 217, 249, 132, 149, 79, 153, 235, 105, 62, 93, 49,
+ 183, 126, 176, 235, 102, 54, 219, 179, 195, 233, 136, 129, 119, 138, 209,
+ 244, 56, 162, 60, 205, 167, 115, 175, 99, 94, 197, 74, 44, 6, 204,
+ 231, 234, 1, 52, 169, 139, 213, 225, 105, 62, 157, 123, 29, 190, 127,
+ 180, 179, 209, 122, 204, 207, 181, 247, 72, 179, 111, 74, 142, 167, 249,
+ 116, 238, 117, 28, 220, 216, 80, 209, 81, 221, 91, 181, 123, 61, 165,
+ 164, 154, 15, 129, 118, 36, 62, 68, 232, 215, 183, 47, 151, 216, 115,
+ 247, 237, 238, 195, 158, 175, 201, 223, 214, 201, 164, 57, 33, 164, 124,
+ 129, 196, 94, 114, 61, 159, 103, 198, 235, 21, 114, 63, 249, 250, 145,
+ 23, 90, 153, 1, 242, 131, 14, 94, 202, 188, 184, 119, 226, 187, 242,
+ 253, 117, 222, 134, 103, 108, 229, 200, 161, 242, 193, 33, 133, 180, 50,
+ 67, 229, 207, 111, 23, 84, 121, 35, 134, 203, 7, 86, 21, 76, 50,
+ 158, 83, 29, 37, 251, 61, 246, 210, 202, 140, 145, 187, 132, 171, 107,
+ 14, 94, 17, 227, 228, 107, 133, 159, 155, 172, 177, 76, 144, 119, 63,
+ 121, 162, 149, 153, 36, 143, 44, 243, 68, 91, 39, 153, 34, 87, 168,
+ 151, 101, 194, 59, 93, 14, 153, 151, 77, 115, 96, 124, 163, 179, 181,
+ 117, 83, 135, 188, 250, 251, 108, 19, 222, 57, 242, 209, 247, 30, 107,
+ 101, 62, 150, 135, 159, 33, 103, 172, 126, 34, 91, 122, 62, 50, 225,
+ 93, 36, 63, 75, 120, 76, 243, 103, 8, 189, 243, 97, 52, 247, 60,
+ 239, 56, 141, 254, 130, 24, 226, 253, 5, 49, 65, 252, 133, 208, 157,
+ 193, 95, 216, 115, 247, 242, 210, 192, 95, 130, 94, 121, 66, 239, 153,
+ 34, 229, 209, 95, 110, 14, 173, 110, 234, 47, 11, 22, 52, 162, 254,
+ 50, 162, 97, 155, 68, 226, 47, 157, 127, 239, 156, 104, 230, 47, 5,
+ 63, 36, 231, 1, 14, 149, 139, 186, 222, 83, 245, 130, 191, 236, 104,
+ 252, 174, 241, 122, 40, 248, 203, 249, 186, 175, 39, 18, 127, 137, 31,
+ 164, 233, 5, 127, 249, 120, 109, 35, 83, 127, 57, 220, 181, 58, 245,
+ 151, 212, 209, 101, 169, 191, 220, 94, 92, 216, 212, 95, 202, 191, 250,
+ 40, 129, 248, 139, 189, 218, 189, 4, 149, 215, 33, 199, 92, 185, 144,
+ 96, 230, 47, 101, 74, 222, 74, 32, 254, 178, 233, 244, 237, 4, 226,
+ 47, 157, 190, 190, 147, 96, 230, 47, 237, 55, 221, 167, 121, 119, 132,
+ 70, 127, 97, 207, 141, 253, 5, 219, 67, 222, 95, 176, 125, 35, 254,
+ 66, 232, 150, 224, 47, 236, 185, 123, 121, 201, 224, 47, 177, 155, 58,
+ 208, 124, 43, 82, 190, 20, 248, 203, 163, 213, 193, 134, 188, 133, 58,
+ 244, 147, 7, 100, 183, 182, 17, 127, 217, 247, 119, 75, 133, 46, 4,
+ 254, 82, 127, 71, 51, 67, 222, 59, 224, 47, 173, 74, 5, 217, 136,
+ 191, 196, 190, 171, 210, 190, 224, 47, 153, 75, 131, 12, 121, 11, 68,
+ 141, 146, 191, 233, 216, 212, 70, 252, 165, 66, 235, 22, 10, 93, 4,
+ 252, 101, 101, 224, 171, 134, 188, 229, 162, 38, 200, 93, 198, 181, 177,
+ 17, 127, 249, 99, 70, 123, 133, 246, 1, 127, 113, 204, 151, 13, 121,
+ 143, 129, 191, 180, 216, 222, 149, 230, 151, 13, 91, 222, 93, 161, 31,
+ 135, 59, 228, 49, 253, 66, 140, 207, 40, 3, 127, 185, 48, 187, 139,
+ 141, 248, 203, 137, 66, 111, 168, 52, 248, 203, 129, 69, 157, 109, 102,
+ 254, 50, 120, 98, 103, 154, 155, 70, 104, 244, 23, 246, 220, 216, 95,
+ 48, 182, 241, 254, 130, 177, 138, 248, 11, 161, 155, 131, 191, 176, 231,
+ 238, 229, 37, 129, 191, 220, 154, 81, 155, 250, 11, 41, 143, 254, 146,
+ 126, 197, 223, 248, 187, 129, 191, 140, 56, 209, 136, 250, 203, 168, 43,
+ 86, 117, 109, 17, 252, 37, 236, 113, 115, 67, 222, 123, 224, 47, 159,
+ 250, 182, 161, 254, 210, 245, 204, 107, 10, 93, 14, 252, 229, 149, 31,
+ 95, 51, 246, 83, 240, 151, 172, 177, 45, 169, 191, 124, 182, 76, 245,
+ 205, 146, 224, 47, 149, 126, 107, 98, 200, 91, 27, 252, 101, 220, 183,
+ 65, 212, 95, 158, 221, 107, 160, 174, 165, 130, 191, 148, 108, 83, 199,
+ 144, 55, 30, 252, 101, 196, 209, 202, 212, 95, 42, 134, 87, 84, 207,
+ 180, 3, 127, 169, 121, 177, 172, 33, 239, 99, 240, 151, 189, 91, 170,
+ 82, 127, 89, 177, 178, 186, 66, 191, 8, 255, 68, 30, 28, 89, 195,
+ 212, 95, 238, 44, 174, 65, 253, 133, 208, 232, 47, 236, 185, 241, 56,
+ 15, 251, 169, 244, 46, 141, 39, 208, 15, 91, 96, 210, 103, 109, 198,
+ 173, 169, 60, 203, 244, 14, 121, 234, 193, 93, 26, 207, 184, 245, 158,
+ 103, 220, 186, 85, 118, 254, 206, 128, 192, 152, 75, 215, 123, 56, 29,
+ 41, 240, 78, 41, 154, 158, 176, 236, 252, 157, 1, 129, 237, 52, 173,
+ 199, 83, 174, 30, 64, 211, 186, 100, 231, 239, 12, 8, 196, 54, 173,
+ 199, 211, 92, 235, 86, 154, 125, 163, 159, 228, 239, 12, 8, 244, 7,
+ 58, 87, 144, 173, 207, 237, 99, 125, 23, 135, 141, 208, 151, 229, 4,
+ 187, 81, 159, 70, 183, 110, 149, 75, 30, 139, 109, 14, 27, 161, 81,
+ 158, 81, 204, 211, 173, 91, 229, 146, 199, 218, 62, 135, 141, 208, 40,
+ 207, 168, 77, 212, 205, 119, 62, 209, 203, 99, 216, 112, 216, 8, 141,
+ 242, 140, 48, 163, 187, 75, 227, 9, 119, 151, 70, 6, 248, 65, 142,
+ 9, 102, 154, 115, 247, 60, 100, 1, 239, 99, 15, 238, 210, 200, 226,
+ 238, 160, 200, 98, 229, 99, 30, 137, 195, 140, 15, 167, 35, 26, 222,
+ 41, 90, 211, 99, 125, 36, 14, 51, 40, 151, 214, 3, 104, 82, 23,
+ 103, 166, 56, 204, 248, 60, 206, 117, 151, 134, 102, 223, 144, 76, 113,
+ 152, 65, 187, 211, 251, 88, 10, 206, 74, 114, 135, 25, 203, 212, 26,
+ 30, 99, 198, 154, 75, 158, 59, 204, 160, 60, 79, 49, 131, 246, 228,
+ 229, 185, 195, 12, 202, 243, 20, 51, 33, 185, 228, 185, 195, 12, 202,
+ 243, 20, 51, 136, 19, 130, 25, 231, 191, 64, 63, 49, 193, 76, 11,
+ 238, 92, 79, 224, 77, 73, 247, 224, 236, 212, 12, 46, 6, 60, 228,
+ 206, 78, 77, 23, 135, 25, 148, 75, 99, 0, 208, 168, 83, 153, 179,
+ 124, 32, 14, 51, 33, 156, 14, 172, 55, 169, 75, 220, 69, 113, 152,
+ 65, 185, 186, 179, 83, 53, 29, 246, 139, 226, 48, 131, 118, 207, 47,
+ 102, 116, 107, 169, 15, 242, 143, 25, 94, 30, 218, 51, 191, 152, 225,
+ 229, 217, 47, 230, 31, 51, 124, 223, 76, 193, 137, 38, 207, 113, 22,
+ 252, 32, 195, 4, 51, 45, 217, 247, 176, 3, 175, 243, 188, 57, 102,
+ 176, 28, 241, 3, 231, 5, 86, 62, 228, 124, 254, 48, 195, 207, 39,
+ 162, 92, 162, 195, 14, 52, 234, 84, 250, 127, 231, 242, 135, 25, 126,
+ 62, 209, 206, 233, 192, 122, 147, 186, 132, 157, 203, 31, 102, 248, 249,
+ 68, 148, 203, 99, 198, 78, 236, 117, 46, 127, 152, 33, 243, 137, 193,
+ 154, 221, 105, 46, 227, 197, 210, 123, 214, 14, 169, 146, 148, 123, 62,
+ 209, 239, 202, 70, 91, 155, 132, 251, 158, 229, 164, 159, 99, 242, 98,
+ 14, 149, 222, 147, 24, 255, 85, 66, 238, 249, 38, 151, 107, 163, 237,
+ 225, 153, 122, 158, 245, 245, 56, 121, 161, 115, 42, 237, 249, 189, 124,
+ 216, 75, 243, 17, 33, 206, 88, 91, 157, 93, 205, 61, 138, 51, 22,
+ 254, 253, 82, 124, 247, 52, 140, 207, 105, 159, 123, 188, 106, 159, 25,
+ 107, 11, 41, 216, 212, 163, 56, 131, 56, 33, 152, 177, 164, 130, 31,
+ 252, 107, 130, 153, 86, 220, 247, 0, 94, 71, 170, 57, 102, 176, 28,
+ 241, 3, 199, 63, 172, 124, 195, 144, 30, 69, 60, 195, 76, 57, 183,
+ 126, 112, 169, 73, 52, 189, 231, 12, 229, 82, 95, 67, 29, 103, 181,
+ 113, 64, 63, 79, 116, 84, 203, 83, 71, 213, 239, 206, 210, 60, 67,
+ 11, 167, 3, 235, 77, 234, 210, 208, 81, 178, 128, 103, 152, 113, 175,
+ 99, 183, 227, 36, 205, 99, 70, 185, 60, 102, 44, 154, 142, 232, 185,
+ 158, 232, 168, 146, 167, 142, 245, 183, 212, 117, 171, 214, 5, 85, 187,
+ 215, 83, 74, 194, 159, 127, 144, 19, 237, 72, 124, 136, 208, 119, 126,
+ 154, 99, 103, 207, 221, 183, 187, 49, 221, 159, 217, 135, 255, 68, 230,
+ 179, 173, 210, 200, 63, 171, 42, 244, 236, 176, 225, 210, 47, 29, 90,
+ 25, 206, 133, 23, 89, 176, 90, 98, 88, 141, 165, 243, 253, 205, 34,
+ 54, 73, 70, 88, 85, 199, 241, 91, 164, 82, 255, 144, 59, 71, 226,
+ 164, 1, 195, 18, 19, 213, 249, 131, 120, 201, 47, 253, 7, 67, 222,
+ 115, 145, 59, 164, 105, 111, 126, 70, 243, 43, 138, 77, 249, 88, 221,
+ 203, 30, 190, 75, 42, 219, 100, 170, 33, 239, 147, 200, 68, 233, 163,
+ 195, 36, 239, 201, 41, 93, 108, 166, 230, 61, 21, 142, 216, 43, 117,
+ 91, 61, 209, 144, 215, 43, 234, 128, 244, 222, 161, 72, 154, 155, 241,
+ 253, 245, 249, 106, 174, 86, 196, 97, 233, 105, 193, 37, 38, 188, 199,
+ 164, 144, 85, 43, 104, 110, 198, 234, 152, 181, 218, 60, 240, 73, 233,
+ 193, 198, 13, 134, 188, 25, 145, 103, 164, 212, 61, 219, 105, 110, 198,
+ 176, 230, 59, 19, 213, 249, 146, 179, 146, 107, 195, 110, 147, 59, 210,
+ 46, 72, 95, 29, 216, 65, 115, 51, 102, 223, 217, 78, 243, 173, 134,
+ 149, 223, 110, 50, 119, 125, 77, 250, 248, 234, 118, 154, 155, 209, 127,
+ 255, 14, 141, 247, 182, 212, 240, 187, 95, 76, 120, 239, 74, 51, 165,
+ 157, 52, 55, 227, 203, 214, 187, 52, 222, 116, 233, 151, 38, 9, 38,
+ 190, 145, 41, 189, 159, 177, 135, 230, 91, 93, 79, 78, 214, 230, 189,
+ 179, 165, 113, 75, 247, 153, 232, 205, 145, 58, 151, 164, 247, 224, 200,
+ 165, 110, 28, 80, 121, 109, 94, 242, 233, 228, 223, 77, 114, 151, 188,
+ 229, 25, 91, 142, 104, 101, 10, 202, 239, 37, 29, 211, 120, 11, 201,
+ 237, 78, 156, 48, 225, 45, 44, 127, 240, 132, 248, 115, 81, 121, 118,
+ 197, 83, 26, 111, 49, 121, 93, 243, 51, 198, 247, 227, 36, 23, 151,
+ 43, 54, 78, 165, 185, 90, 141, 186, 158, 215, 214, 23, 74, 203, 195,
+ 162, 174, 154, 212, 183, 172, 204, 214, 217, 124, 41, 189, 243, 97, 69,
+ 217, 108, 253, 141, 180, 37, 216, 190, 146, 182, 228, 83, 104, 75, 176,
+ 189, 36, 109, 9, 161, 59, 196, 205, 177, 179, 231, 238, 229, 237, 237,
+ 245, 204, 126, 252, 139, 158, 193, 164, 45, 57, 176, 188, 168, 66, 119,
+ 156, 48, 92, 74, 159, 30, 214, 214, 136, 119, 55, 180, 37, 44, 78,
+ 199, 210, 181, 160, 210, 208, 150, 24, 197, 105, 228, 189, 11, 109, 73,
+ 124, 106, 8, 109, 75, 126, 156, 240, 182, 134, 143, 120, 233, 131, 226,
+ 131, 77, 124, 109, 135, 52, 107, 109, 8, 109, 75, 202, 58, 186, 104,
+ 190, 182, 75, 250, 97, 144, 108, 194, 155, 40, 77, 43, 222, 134, 182,
+ 37, 171, 59, 183, 208, 120, 247, 74, 206, 168, 198, 38, 188, 7, 164,
+ 227, 15, 26, 210, 182, 228, 171, 9, 117, 105, 238, 230, 136, 7, 53,
+ 77, 120, 143, 73, 175, 12, 172, 74, 219, 146, 161, 49, 149, 104, 238,
+ 230, 230, 75, 190, 166, 121, 94, 231, 173, 190, 180, 45, 249, 62, 172,
+ 28, 205, 221, 28, 23, 231, 99, 194, 123, 65, 90, 50, 189, 20, 109,
+ 75, 92, 165, 74, 210, 182, 164, 233, 250, 226, 166, 109, 201, 129, 2,
+ 37, 104, 91, 242, 226, 151, 162, 180, 45, 121, 237, 67, 179, 181, 172,
+ 187, 210, 241, 172, 23, 9, 164, 45, 217, 182, 240, 169, 182, 150, 149,
+ 46, 173, 170, 254, 56, 193, 172, 45, 121, 113, 144, 148, 201, 146, 246,
+ 78, 126, 164, 173, 101, 101, 75, 243, 234, 102, 38, 152, 181, 37, 75,
+ 207, 166, 145, 50, 114, 165, 121, 15, 19, 72, 91, 18, 211, 228, 81,
+ 130, 89, 91, 98, 77, 240, 162, 109, 201, 188, 185, 222, 180, 45, 57,
+ 219, 189, 128, 105, 91, 210, 179, 49, 169, 111, 81, 121, 228, 68, 173,
+ 190, 208, 150, 68, 237, 124, 108, 162, 183, 184, 60, 106, 47, 25, 11,
+ 150, 148, 151, 206, 85, 223, 25, 219, 146, 127, 139, 62, 77, 48, 107,
+ 75, 216, 26, 172, 47, 165, 177, 45, 49, 91, 155, 165, 253, 18, 232,
+ 71, 145, 182, 36, 182, 78, 144, 19, 251, 69, 164, 45, 33, 244, 244,
+ 77, 115, 236, 236, 121, 30, 253, 146, 218, 207, 236, 21, 178, 11, 208,
+ 60, 175, 45, 251, 212, 245, 151, 209, 93, 135, 75, 223, 252, 211, 199,
+ 112, 44, 121, 173, 195, 106, 137, 245, 209, 99, 233, 58, 97, 161, 197,
+ 155, 36, 163, 62, 58, 242, 214, 141, 216, 34, 141, 248, 203, 199, 70,
+ 218, 146, 33, 146, 218, 55, 143, 152, 26, 47, 45, 31, 243, 143, 225,
+ 125, 124, 161, 51, 119, 72, 133, 238, 110, 111, 79, 218, 146, 8, 251,
+ 6, 133, 94, 56, 115, 151, 116, 251, 208, 74, 67, 222, 59, 208, 150,
+ 164, 126, 176, 170, 61, 105, 75, 174, 94, 93, 171, 208, 242, 236, 189,
+ 210, 226, 177, 223, 25, 242, 78, 135, 126, 201, 167, 111, 253, 210, 158,
+ 180, 37, 141, 55, 236, 83, 232, 25, 208, 150, 92, 205, 78, 49, 228,
+ 173, 62, 231, 152, 228, 19, 120, 169, 61, 105, 75, 14, 44, 73, 87,
+ 232, 165, 208, 150, 148, 125, 225, 101, 104, 171, 249, 17, 103, 164, 118,
+ 153, 229, 104, 126, 217, 166, 132, 10, 218, 58, 231, 89, 169, 175, 163,
+ 178, 33, 239, 120, 104, 75, 126, 241, 41, 77, 243, 203, 126, 237, 95,
+ 66, 161, 127, 10, 191, 44, 197, 125, 83, 212, 120, 125, 21, 218, 146,
+ 58, 43, 138, 210, 252, 178, 42, 13, 84, 186, 0, 180, 37, 229, 118,
+ 22, 49, 228, 45, 29, 117, 87, 202, 172, 88, 132, 230, 151, 253, 25,
+ 164, 242, 250, 67, 91, 178, 95, 46, 102, 200, 155, 5, 109, 201, 193,
+ 147, 37, 105, 126, 89, 245, 63, 213, 247, 127, 16, 158, 45, 133, 158,
+ 240, 49, 228, 189, 14, 109, 201, 200, 26, 229, 105, 126, 217, 249, 59,
+ 42, 157, 211, 222, 75, 238, 188, 219, 215, 120, 109, 49, 217, 91, 254,
+ 99, 79, 121, 154, 95, 22, 189, 86, 45, 95, 30, 218, 146, 225, 225,
+ 21, 140, 215, 248, 146, 11, 203, 83, 23, 85, 178, 145, 182, 228, 135,
+ 69, 234, 186, 91, 16, 180, 37, 95, 46, 126, 197, 120, 173, 13, 218,
+ 146, 208, 183, 234, 208, 220, 52, 185, 159, 186, 62, 120, 46, 188, 180,
+ 60, 175, 151, 241, 218, 226, 83, 104, 75, 216, 250, 188, 47, 165, 19,
+ 161, 45, 49, 91, 183, 167, 253, 146, 185, 172, 45, 105, 1, 253, 18,
+ 28, 255, 144, 182, 132, 208, 163, 96, 140, 195, 158, 231, 129, 203, 174,
+ 207, 236, 75, 94, 244, 164, 109, 73, 137, 141, 109, 21, 186, 227, 251,
+ 195, 165, 37, 75, 234, 27, 242, 206, 124, 123, 181, 196, 198, 231, 177,
+ 116, 13, 121, 251, 252, 77, 146, 209, 248, 28, 121, 83, 103, 110, 145,
+ 118, 132, 134, 208, 182, 228, 234, 113, 245, 238, 177, 47, 167, 197, 75,
+ 233, 5, 140, 239, 42, 43, 229, 216, 33, 121, 183, 30, 71, 243, 77,
+ 91, 188, 170, 222, 49, 182, 28, 198, 56, 75, 154, 79, 50, 241, 211,
+ 68, 105, 209, 70, 146, 119, 232, 148, 98, 98, 62, 82, 104, 43, 244,
+ 75, 190, 91, 101, 124, 87, 89, 61, 104, 75, 166, 45, 26, 71, 115,
+ 85, 15, 37, 140, 86, 232, 14, 208, 150, 124, 123, 119, 164, 33, 239,
+ 183, 48, 198, 217, 51, 114, 24, 205, 85, 181, 134, 170, 57, 148, 31,
+ 67, 91, 210, 237, 77, 227, 251, 213, 150, 58, 206, 72, 101, 175, 246,
+ 162, 109, 73, 223, 134, 61, 105, 91, 50, 127, 108, 119, 67, 222, 221,
+ 208, 150, 148, 94, 208, 151, 182, 37, 171, 6, 189, 169, 249, 233, 101,
+ 233, 204, 107, 253, 141, 207, 213, 133, 182, 196, 225, 223, 159, 182, 37,
+ 139, 199, 246, 183, 145, 126, 201, 202, 159, 251, 155, 172, 189, 223, 149,
+ 54, 86, 27, 64, 219, 146, 65, 131, 212, 242, 229, 161, 45, 241, 221,
+ 248, 150, 33, 239, 51, 104, 75, 198, 119, 239, 71, 219, 146, 215, 239,
+ 171, 49, 237, 41, 180, 37, 117, 63, 239, 109, 200, 251, 16, 218, 146,
+ 90, 119, 122, 209, 182, 228, 243, 190, 42, 253, 2, 218, 146, 194, 187,
+ 123, 26, 242, 122, 67, 91, 18, 242, 110, 47, 218, 150, 12, 140, 83,
+ 203, 151, 132, 182, 100, 68, 33, 99, 222, 74, 208, 150, 252, 247, 101,
+ 119, 218, 150, 252, 217, 90, 221, 47, 82, 7, 218, 146, 174, 169, 175,
+ 27, 242, 150, 129, 49, 78, 70, 175, 14, 180, 45, 249, 40, 198, 166,
+ 237, 17, 41, 45, 151, 149, 90, 219, 204, 250, 37, 108, 239, 134, 47,
+ 165, 127, 131, 182, 196, 108, 79, 7, 153, 35, 195, 121, 49, 186, 22,
+ 115, 42, 211, 219, 113, 214, 100, 142, 172, 53, 155, 127, 113, 252, 13,
+ 101, 255, 50, 159, 35, 195, 114, 116, 222, 231, 111, 86, 62, 250, 140,
+ 184, 181, 24, 11, 167, 195, 1, 239, 228, 208, 244, 248, 157, 17, 183,
+ 22, 131, 114, 105, 61, 176, 222, 154, 142, 184, 211, 226, 214, 98, 44,
+ 127, 233, 231, 200, 28, 154, 125, 237, 167, 197, 173, 197, 160, 221, 69,
+ 174, 95, 250, 157, 17, 187, 126, 137, 246, 20, 185, 126, 105, 63, 45,
+ 118, 253, 18, 113, 66, 243, 238, 238, 195, 119, 73, 53, 193, 204, 107,
+ 220, 58, 1, 240, 58, 255, 244, 96, 45, 230, 20, 183, 134, 113, 146,
+ 91, 139, 249, 83, 28, 102, 80, 46, 93, 139, 1, 26, 117, 42, 145,
+ 34, 69, 28, 102, 236, 156, 14, 172, 55, 169, 75, 88, 138, 56, 204,
+ 160, 92, 221, 90, 140, 166, 35, 238, 190, 56, 204, 160, 221, 69, 174,
+ 95, 162, 141, 69, 174, 95, 134, 165, 136, 93, 191, 68, 219, 137, 92,
+ 191, 68, 156, 208, 187, 31, 111, 131, 31, 156, 50, 198, 76, 83, 43,
+ 151, 19, 118, 47, 211, 219, 122, 215, 131, 187, 31, 239, 113, 121, 119,
+ 247, 184, 187, 31, 239, 228, 15, 51, 55, 35, 70, 179, 220, 107, 78,
+ 71, 28, 188, 83, 156, 166, 39, 228, 78, 254, 48, 83, 48, 229, 14,
+ 93, 239, 65, 185, 180, 30, 64, 147, 186, 184, 254, 203, 31, 102, 90,
+ 54, 255, 182, 61, 173, 199, 221, 92, 121, 119, 154, 125, 195, 254, 203,
+ 31, 102, 66, 155, 126, 196, 238, 126, 188, 195, 249, 144, 238, 207, 97,
+ 67, 155, 18, 58, 47, 61, 47, 237, 67, 49, 144, 135, 246, 251, 159,
+ 202, 67, 123, 230, 37, 15, 109, 245, 63, 149, 23, 102, 32, 15, 237,
+ 226, 169, 60, 122, 247, 227, 109, 238, 28, 145, 235, 224, 7, 247, 77,
+ 48, 195, 229, 16, 133, 1, 111, 218, 77, 15, 238, 126, 188, 205, 229,
+ 94, 223, 226, 238, 126, 188, 41, 46, 206, 160, 92, 154, 123, 13, 52,
+ 234, 196, 50, 62, 55, 197, 197, 153, 48, 78, 7, 214, 155, 212, 37,
+ 230, 134, 184, 56, 131, 114, 117, 119, 63, 106, 58, 172, 55, 196, 197,
+ 25, 180, 187, 200, 56, 227, 115, 83, 108, 156, 65, 123, 138, 140, 51,
+ 214, 27, 98, 227, 12, 226, 132, 158, 35, 114, 25, 252, 224, 182, 9,
+ 102, 184, 61, 204, 86, 224, 141, 187, 234, 193, 221, 143, 215, 185, 24,
+ 112, 141, 59, 71, 228, 170, 56, 204, 160, 92, 26, 3, 128, 70, 157,
+ 202, 236, 193, 21, 113, 152, 177, 114, 58, 176, 222, 164, 46, 161, 87,
+ 196, 97, 6, 229, 234, 206, 17, 209, 116, 164, 93, 22, 135, 25, 180,
+ 187, 200, 241, 12, 218, 88, 228, 120, 38, 244, 138, 216, 241, 12, 218,
+ 78, 228, 120, 6, 113, 66, 207, 201, 223, 14, 126, 112, 61, 47, 204,
+ 96, 122, 247, 36, 221, 29, 70, 105, 151, 50, 189, 99, 246, 120, 112,
+ 247, 227, 37, 46, 6, 92, 98, 229, 125, 18, 61, 197, 76, 113, 183,
+ 126, 112, 241, 200, 183, 236, 254, 95, 78, 71, 154, 11, 176, 175, 233,
+ 113, 236, 242, 20, 51, 238, 117, 212, 72, 232, 69, 117, 160, 92, 154,
+ 15, 11, 245, 38, 117, 73, 251, 213, 83, 204, 184, 215, 145, 22, 104,
+ 163, 152, 65, 185, 186, 115, 68, 92, 26, 46, 119, 120, 138, 25, 247,
+ 58, 106, 206, 87, 247, 150, 13, 240, 86, 237, 94, 79, 41, 169, 230,
+ 6, 161, 29, 137, 15, 17, 26, 115, 85, 217, 243, 60, 246, 96, 244,
+ 124, 77, 110, 182, 245, 59, 173, 76, 119, 153, 148, 247, 78, 236, 37,
+ 175, 94, 107, 204, 139, 185, 135, 255, 6, 146, 50, 3, 100, 111, 199,
+ 122, 141, 247, 93, 185, 254, 233, 117, 38, 188, 161, 242, 133, 229, 49,
+ 90, 153, 161, 242, 157, 37, 223, 168, 231, 103, 63, 27, 41, 255, 216,
+ 116, 173, 33, 111, 78, 129, 241, 242, 204, 97, 107, 180, 50, 147, 228,
+ 137, 151, 190, 106, 167, 174, 35, 78, 150, 39, 56, 190, 106, 103, 188,
+ 142, 56, 69, 94, 113, 118, 149, 86, 102, 154, 220, 232, 232, 42, 141,
+ 119, 186, 188, 63, 113, 149, 9, 239, 12, 121, 247, 8, 34, 127, 150,
+ 156, 241, 190, 74, 99, 174, 106, 106, 43, 99, 189, 152, 123, 88, 188,
+ 225, 74, 173, 204, 199, 114, 249, 186, 43, 53, 189, 243, 229, 74, 181,
+ 87, 154, 232, 253, 68, 62, 148, 78, 202, 44, 148, 155, 13, 39, 239,
+ 188, 72, 94, 243, 143, 89, 125, 23, 203, 245, 45, 223, 104, 101, 150,
+ 80, 250, 252, 244, 165, 220, 243, 188, 99, 60, 250, 26, 226, 143, 247,
+ 53, 196, 19, 241, 53, 66, 163, 175, 177, 231, 121, 251, 218, 241, 211,
+ 125, 169, 175, 145, 242, 232, 107, 131, 110, 247, 52, 245, 53, 235, 244,
+ 238, 212, 215, 42, 87, 235, 74, 125, 205, 146, 248, 186, 169, 175, 157,
+ 121, 210, 129, 250, 90, 253, 2, 18, 245, 181, 101, 101, 218, 153, 250,
+ 90, 215, 203, 173, 169, 175, 213, 28, 222, 156, 250, 154, 111, 145, 102,
+ 166, 190, 246, 188, 105, 19, 234, 107, 203, 150, 52, 166, 190, 214, 240,
+ 191, 70, 166, 190, 118, 119, 112, 99, 234, 107, 199, 107, 88, 169, 175,
+ 245, 41, 253, 170, 169, 175, 157, 146, 122, 82, 95, 251, 171, 106, 79,
+ 234, 107, 3, 138, 244, 52, 245, 181, 234, 150, 14, 212, 215, 158, 92,
+ 104, 71, 125, 237, 239, 221, 173, 77, 125, 109, 102, 251, 102, 212, 215,
+ 8, 141, 190, 198, 158, 27, 251, 26, 182, 195, 188, 175, 97, 187, 74,
+ 124, 141, 208, 232, 107, 236, 121, 222, 190, 246, 90, 57, 27, 205, 121,
+ 36, 229, 209, 215, 42, 52, 53, 230, 69, 95, 251, 118, 128, 141, 230,
+ 60, 254, 213, 202, 70, 115, 30, 139, 85, 48, 227, 13, 149, 71, 174,
+ 104, 79, 115, 30, 219, 13, 104, 111, 35, 190, 246, 118, 161, 246, 54,
+ 51, 95, 203, 153, 210, 142, 230, 45, 206, 58, 167, 210, 232, 107, 107,
+ 50, 140, 215, 22, 45, 201, 83, 228, 31, 187, 18, 249, 211, 228, 158,
+ 27, 84, 218, 27, 124, 45, 221, 203, 248, 157, 189, 146, 103, 200, 195,
+ 234, 216, 105, 206, 99, 153, 37, 54, 109, 141, 202, 33, 175, 107, 221,
+ 206, 100, 205, 122, 142, 188, 243, 68, 19, 154, 243, 248, 196, 170, 230,
+ 135, 150, 5, 95, 91, 61, 200, 106, 200, 91, 60, 249, 19, 185, 120,
+ 253, 86, 54, 226, 107, 91, 195, 213, 92, 209, 226, 224, 107, 43, 206,
+ 180, 55, 121, 231, 197, 114, 131, 83, 175, 211, 124, 73, 66, 163, 175,
+ 177, 231, 198, 190, 134, 241, 152, 247, 53, 140, 175, 196, 215, 8, 141,
+ 190, 198, 158, 231, 237, 107, 43, 86, 55, 164, 190, 70, 202, 163, 175,
+ 21, 153, 211, 208, 212, 215, 42, 191, 219, 144, 250, 218, 250, 143, 27,
+ 82, 95, 11, 138, 111, 104, 234, 107, 17, 93, 253, 89, 62, 246, 74,
+ 127, 234, 107, 11, 159, 251, 155, 250, 90, 181, 31, 2, 168, 175, 77,
+ 234, 16, 64, 125, 173, 120, 64, 128, 169, 175, 21, 62, 238, 79, 125,
+ 173, 205, 40, 127, 234, 107, 227, 10, 250, 155, 250, 218, 210, 63, 26,
+ 80, 95, 235, 57, 80, 173, 99, 69, 240, 181, 208, 95, 140, 245, 222,
+ 6, 95, 155, 181, 160, 53, 245, 53, 223, 94, 42, 93, 14, 124, 237,
+ 98, 83, 227, 181, 54, 31, 240, 181, 198, 63, 55, 163, 190, 246, 239,
+ 127, 141, 52, 63, 93, 36, 151, 169, 239, 111, 178, 182, 184, 88, 158,
+ 50, 132, 229, 230, 18, 26, 125, 141, 61, 55, 30, 215, 98, 191, 156,
+ 244, 209, 99, 78, 64, 191, 243, 178, 89, 31, 157, 221, 153, 24, 10,
+ 188, 174, 120, 243, 62, 58, 150, 163, 231, 35, 109, 99, 229, 195, 226,
+ 243, 55, 174, 197, 126, 2, 61, 31, 105, 27, 119, 62, 18, 208, 168,
+ 83, 41, 20, 159, 191, 113, 45, 198, 7, 90, 15, 78, 7, 214, 155,
+ 212, 37, 250, 231, 252, 141, 107, 177, 93, 160, 245, 136, 207, 117, 47,
+ 143, 166, 195, 239, 231, 252, 141, 107, 209, 31, 232, 124, 98, 188, 62,
+ 87, 149, 245, 183, 28, 54, 66, 63, 233, 144, 96, 55, 234, 135, 233,
+ 242, 43, 114, 201, 99, 49, 213, 97, 35, 52, 202, 51, 138, 181, 186,
+ 92, 218, 159, 245, 242, 88, 187, 233, 176, 17, 26, 229, 25, 181, 167,
+ 186, 117, 196, 92, 242, 24, 54, 28, 54, 66, 163, 60, 35, 204, 240,
+ 227, 90, 196, 9, 61, 235, 239, 8, 248, 193, 118, 51, 204, 176, 59,
+ 19, 253, 128, 55, 230, 152, 57, 102, 176, 28, 29, 15, 30, 231, 206,
+ 250, 59, 38, 14, 51, 40, 151, 158, 143, 4, 52, 234, 84, 214, 53,
+ 142, 138, 195, 140, 31, 167, 3, 235, 77, 234, 18, 114, 84, 28, 102,
+ 80, 174, 238, 158, 81, 77, 135, 235, 136, 56, 204, 160, 221, 233, 220,
+ 200, 11, 103, 123, 119, 152, 177, 76, 253, 215, 230, 41, 102, 208, 198,
+ 188, 60, 119, 152, 65, 121, 158, 98, 38, 132, 151, 247, 212, 217, 222,
+ 29, 102, 28, 147, 255, 181, 121, 138, 25, 180, 29, 149, 247, 196, 217,
+ 222, 29, 102, 44, 32, 207, 83, 204, 32, 78, 232, 89, 127, 191, 131,
+ 31, 156, 48, 195, 12, 187, 51, 209, 117, 24, 218, 243, 63, 204, 49,
+ 131, 229, 104, 12, 56, 204, 157, 245, 119, 72, 28, 102, 66, 57, 29,
+ 46, 120, 39, 151, 166, 199, 113, 72, 28, 102, 80, 46, 173, 7, 208,
+ 164, 46, 62, 135, 196, 97, 38, 244, 143, 92, 103, 253, 105, 246, 141,
+ 249, 93, 28, 102, 208, 238, 249, 197, 12, 63, 167, 239, 56, 148, 127,
+ 204, 232, 214, 48, 14, 229, 31, 51, 186, 53, 140, 223, 243, 143, 25,
+ 190, 111, 134, 56, 161, 243, 167, 123, 193, 15, 142, 152, 97, 134, 221,
+ 153, 24, 115, 16, 218, 243, 3, 30, 156, 245, 119, 144, 139, 1, 7,
+ 185, 123, 70, 247, 231, 15, 51, 252, 252, 169, 31, 167, 35, 6, 222,
+ 41, 70, 211, 99, 223, 159, 63, 204, 240, 243, 167, 40, 151, 214, 3,
+ 104, 82, 151, 148, 125, 249, 195, 12, 63, 127, 234, 119, 32, 215, 89,
+ 127, 154, 125, 67, 247, 229, 15, 51, 100, 254, 52, 88, 179, 59, 241,
+ 33, 151, 179, 244, 158, 11, 15, 55, 188, 52, 127, 234, 227, 218, 104,
+ 235, 28, 240, 173, 71, 113, 193, 158, 75, 158, 213, 58, 224, 165, 57,
+ 50, 148, 215, 179, 68, 79, 143, 228, 161, 61, 169, 188, 51, 165, 247,
+ 76, 170, 213, 241, 165, 121, 16, 235, 229, 141, 182, 98, 141, 219, 123,
+ 20, 103, 66, 57, 121, 150, 11, 165, 247, 140, 247, 169, 251, 210, 88,
+ 215, 5, 242, 126, 24, 237, 239, 81, 156, 65, 156, 208, 190, 153, 19,
+ 252, 224, 119, 51, 204, 180, 98, 125, 109, 224, 117, 57, 61, 24, 207,
+ 236, 229, 98, 64, 50, 135, 153, 237, 111, 228, 43, 55, 119, 67, 115,
+ 7, 187, 103, 52, 153, 139, 1, 64, 163, 78, 44, 83, 249, 183, 55,
+ 242, 149, 155, 59, 171, 111, 122, 27, 90, 15, 78, 7, 214, 155, 212,
+ 37, 174, 69, 191, 34, 158, 97, 198, 189, 142, 7, 95, 165, 208, 220,
+ 92, 148, 171, 27, 207, 104, 58, 42, 191, 230, 137, 142, 188, 115, 115,
+ 235, 220, 102, 185, 185, 104, 119, 178, 111, 125, 140, 127, 144, 19, 237,
+ 72, 124, 136, 208, 13, 227, 230, 216, 217, 115, 247, 237, 238, 245, 158,
+ 207, 236, 163, 250, 44, 210, 112, 96, 149, 252, 71, 196, 42, 244, 43,
+ 19, 134, 75, 253, 3, 14, 25, 198, 148, 39, 11, 86, 75, 12, 171,
+ 177, 116, 125, 195, 43, 98, 147, 100, 132, 85, 139, 150, 155, 187, 241,
+ 147, 245, 90, 153, 56, 201, 49, 120, 189, 118, 103, 103, 188, 244, 118,
+ 240, 122, 67, 222, 130, 81, 59, 164, 6, 161, 223, 107, 101, 118, 74,
+ 227, 178, 212, 88, 90, 46, 98, 151, 52, 55, 218, 120, 14, 190, 100,
+ 84, 162, 20, 252, 39, 169, 175, 83, 170, 58, 106, 150, 66, 151, 136,
+ 216, 43, 37, 53, 30, 100, 200, 123, 55, 242, 128, 244, 251, 169, 102,
+ 244, 126, 211, 33, 213, 171, 41, 244, 131, 240, 195, 82, 167, 225, 5,
+ 140, 231, 219, 35, 143, 73, 207, 236, 46, 45, 31, 41, 69, 250, 233,
+ 120, 106, 176, 90, 223, 147, 210, 236, 247, 254, 52, 204, 83, 194, 251,
+ 77, 99, 122, 220, 209, 202, 164, 74, 37, 94, 188, 80, 232, 130, 17,
+ 103, 165, 158, 169, 197, 12, 245, 122, 71, 93, 144, 122, 44, 173, 76,
+ 239, 55, 109, 211, 161, 65, 59, 149, 247, 178, 212, 229, 113, 75, 67,
+ 222, 167, 145, 215, 164, 202, 75, 122, 208, 251, 77, 39, 253, 248, 174,
+ 66, 63, 15, 191, 45, 109, 56, 52, 202, 144, 55, 59, 242, 174, 212,
+ 220, 54, 141, 222, 111, 218, 247, 105, 184, 118, 175, 106, 186, 180, 237,
+ 92, 164, 137, 111, 100, 74, 33, 187, 29, 90, 153, 44, 233, 122, 249,
+ 72, 109, 190, 61, 91, 154, 53, 198, 140, 55, 71, 106, 84, 51, 138,
+ 148, 145, 103, 204, 136, 210, 230, 204, 189, 228, 223, 207, 68, 153, 204,
+ 153, 123, 203, 62, 79, 72, 153, 130, 114, 177, 97, 115, 52, 222, 66,
+ 114, 129, 63, 231, 24, 223, 65, 155, 92, 88, 94, 244, 23, 41, 83,
+ 84, 254, 176, 228, 199, 234, 59, 219, 138, 201, 221, 228, 79, 76, 244,
+ 22, 151, 11, 93, 248, 84, 43, 83, 82, 94, 21, 242, 153, 134, 163,
+ 210, 114, 210, 171, 95, 154, 212, 183, 172, 204, 214, 21, 125, 41, 141,
+ 249, 116, 102, 235, 141, 164, 45, 193, 246, 149, 180, 37, 227, 160, 45,
+ 193, 246, 146, 180, 37, 132, 182, 66, 91, 194, 158, 187, 151, 87, 165,
+ 215, 51, 123, 175, 13, 163, 105, 91, 50, 45, 64, 189, 11, 248, 85,
+ 104, 75, 134, 118, 93, 107, 218, 150, 176, 56, 29, 75, 215, 175, 176,
+ 45, 49, 138, 211, 164, 45, 249, 75, 238, 69, 219, 146, 35, 187, 180,
+ 181, 44, 104, 75, 156, 205, 66, 76, 238, 14, 222, 33, 149, 217, 223,
+ 151, 182, 37, 191, 84, 82, 121, 139, 64, 91, 210, 103, 116, 87, 67,
+ 222, 98, 208, 150, 92, 94, 101, 163, 109, 201, 133, 77, 234, 58, 82,
+ 41, 104, 75, 218, 236, 174, 102, 200, 155, 14, 109, 73, 151, 198, 55,
+ 131, 73, 91, 178, 222, 251, 160, 66, 103, 65, 91, 210, 48, 245, 91,
+ 195, 246, 0, 243, 252, 111, 102, 174, 161, 109, 201, 205, 143, 230, 40,
+ 116, 97, 104, 75, 250, 92, 236, 107, 200, 251, 56, 242, 140, 148, 253,
+ 243, 218, 182, 164, 45, 233, 52, 231, 23, 133, 46, 15, 109, 201, 157,
+ 126, 199, 13, 99, 197, 147, 200, 11, 82, 192, 189, 185, 193, 164, 45,
+ 185, 228, 245, 131, 122, 172, 92, 248, 101, 233, 156, 239, 49, 67, 189,
+ 89, 120, 95, 91, 208, 189, 96, 210, 150, 196, 84, 206, 86, 105, 204,
+ 167, 243, 46, 96, 242, 125, 239, 74, 25, 201, 207, 130, 73, 91, 50,
+ 127, 177, 202, 139, 121, 254, 85, 251, 103, 25, 234, 125, 1, 109, 73,
+ 235, 110, 15, 130, 73, 91, 210, 219, 245, 72, 107, 119, 179, 165, 113,
+ 147, 159, 5, 155, 181, 37, 251, 211, 139, 210, 182, 228, 148, 179, 52,
+ 109, 75, 46, 45, 241, 53, 109, 75, 234, 204, 170, 74, 219, 146, 200,
+ 106, 53, 104, 91, 242, 239, 174, 90, 166, 109, 73, 163, 243, 181, 105,
+ 91, 210, 108, 87, 3, 141, 183, 152, 220, 230, 203, 32, 211, 182, 100,
+ 119, 242, 171, 180, 45, 137, 255, 43, 152, 182, 37, 171, 44, 175, 155,
+ 182, 37, 108, 221, 216, 151, 210, 216, 150, 152, 173, 39, 211, 126, 9,
+ 244, 163, 104, 91, 82, 43, 200, 137, 253, 34, 210, 150, 16, 58, 251,
+ 135, 57, 118, 246, 220, 189, 188, 229, 85, 159, 217, 83, 215, 22, 167,
+ 249, 116, 111, 157, 85, 207, 16, 61, 60, 116, 184, 116, 178, 150, 113,
+ 110, 110, 111, 104, 75, 88, 31, 61, 150, 174, 79, 214, 129, 182, 196,
+ 168, 143, 174, 174, 107, 108, 145, 58, 124, 222, 134, 230, 211, 181, 169,
+ 168, 158, 141, 186, 0, 218, 146, 59, 171, 140, 207, 198, 13, 158, 183,
+ 67, 250, 127, 180, 93, 7, 96, 83, 213, 215, 191, 73, 10, 5, 25,
+ 22, 68, 134, 50, 202, 134, 50, 236, 96, 183, 205, 107, 203, 222, 5,
+ 10, 20, 16, 218, 180, 73, 219, 208, 54, 9, 73, 186, 24, 109, 5,
+ 100, 201, 222, 178, 172, 34, 75, 65, 202, 80, 144, 182, 73, 4, 65,
+ 28, 104, 21, 197, 173, 117, 15, 80, 64, 101, 202, 248, 126, 231, 190,
+ 151, 151, 87, 90, 192, 127, 202, 39, 158, 247, 206, 189, 239, 222, 223,
+ 29, 231, 220, 115, 206, 125, 35, 29, 254, 122, 31, 249, 123, 186, 17,
+ 11, 196, 103, 28, 123, 230, 30, 137, 92, 217, 227, 222, 207, 83, 246,
+ 228, 151, 68, 254, 56, 180, 190, 252, 61, 93, 181, 29, 62, 156, 159,
+ 63, 227, 104, 228, 219, 93, 254, 188, 231, 247, 181, 219, 242, 143, 71,
+ 118, 218, 125, 90, 254, 54, 183, 223, 23, 14, 206, 175, 157, 249, 78,
+ 100, 78, 139, 151, 238, 89, 215, 153, 123, 42, 178, 235, 147, 75, 228,
+ 111, 115, 127, 253, 105, 129, 86, 28, 239, 71, 145, 51, 236, 115, 239,
+ 89, 247, 16, 226, 146, 226, 186, 107, 181, 110, 91, 210, 98, 206, 11,
+ 156, 255, 3, 182, 228, 224, 237, 87, 238, 89, 247, 2, 226, 146, 209,
+ 139, 223, 208, 186, 109, 73, 75, 149, 216, 127, 29, 226, 146, 174, 121,
+ 63, 222, 179, 110, 108, 222, 79, 145, 51, 252, 85, 242, 247, 116, 23,
+ 198, 87, 231, 252, 161, 153, 191, 71, 118, 157, 95, 235, 158, 243, 252,
+ 14, 108, 201, 190, 149, 53, 229, 239, 233, 178, 54, 139, 58, 86, 15,
+ 182, 164, 203, 206, 123, 215, 125, 104, 246, 165, 72, 221, 222, 58, 242,
+ 247, 116, 117, 103, 60, 44, 126, 243, 13, 91, 114, 124, 192, 189, 127,
+ 143, 246, 91, 216, 18, 125, 138, 252, 13, 110, 212, 147, 49, 226, 55,
+ 181, 55, 180, 170, 168, 254, 17, 13, 239, 251, 61, 157, 254, 90, 3,
+ 249, 123, 186, 174, 39, 164, 111, 160, 97, 75, 124, 87, 221, 187, 110,
+ 27, 216, 18, 231, 134, 198, 242, 247, 116, 23, 183, 61, 206, 249, 39,
+ 96, 75, 206, 239, 187, 247, 61, 153, 27, 176, 37, 27, 95, 106, 227,
+ 249, 187, 145, 7, 197, 189, 233, 153, 89, 117, 163, 118, 159, 12, 188,
+ 239, 183, 185, 158, 247, 2, 26, 200, 60, 125, 155, 123, 191, 247, 5,
+ 228, 184, 164, 183, 199, 150, 44, 233, 208, 217, 69, 251, 31, 183, 45,
+ 113, 243, 189, 246, 206, 137, 240, 228, 87, 142, 247, 225, 192, 27, 17,
+ 139, 26, 14, 149, 109, 201, 141, 111, 196, 53, 186, 214, 148, 20, 249,
+ 122, 192, 189, 159, 55, 54, 134, 45, 241, 236, 207, 119, 202, 207, 159,
+ 187, 194, 150, 220, 107, 127, 238, 182, 37, 221, 236, 93, 100, 91, 178,
+ 166, 187, 248, 108, 62, 6, 182, 164, 213, 149, 123, 207, 223, 19, 115,
+ 95, 141, 108, 241, 240, 19, 178, 45, 177, 159, 21, 127, 127, 249, 218,
+ 83, 71, 34, 223, 253, 236, 222, 191, 43, 190, 43, 175, 36, 242, 229,
+ 95, 163, 101, 91, 178, 180, 233, 68, 206, 111, 134, 45, 169, 43, 36,
+ 222, 179, 110, 45, 196, 37, 246, 243, 41, 242, 183, 185, 250, 254, 233,
+ 156, 95, 128, 184, 228, 139, 245, 247, 254, 174, 119, 29, 246, 56, 199,
+ 143, 102, 200, 223, 230, 198, 46, 201, 20, 127, 219, 26, 182, 228, 253,
+ 241, 89, 247, 172, 219, 28, 182, 164, 217, 71, 118, 249, 219, 220, 129,
+ 210, 247, 196, 97, 176, 37, 173, 76, 150, 123, 214, 157, 10, 91, 18,
+ 215, 38, 93, 254, 54, 247, 233, 127, 196, 254, 79, 132, 45, 73, 56,
+ 166, 191, 103, 93, 1, 113, 73, 217, 208, 39, 101, 91, 114, 121, 252,
+ 4, 206, 111, 192, 30, 39, 197, 112, 239, 239, 107, 207, 195, 150, 20,
+ 133, 142, 151, 109, 9, 203, 27, 39, 253, 13, 218, 191, 34, 7, 30,
+ 29, 123, 159, 239, 122, 47, 69, 126, 49, 203, 243, 109, 174, 35, 114,
+ 140, 108, 75, 182, 84, 27, 125, 159, 118, 111, 70, 46, 125, 211, 243,
+ 109, 174, 230, 49, 145, 191, 5, 91, 146, 107, 30, 113, 159, 103, 254,
+ 234, 40, 123, 140, 231, 219, 220, 126, 71, 60, 223, 230, 214, 241, 191,
+ 119, 221, 198, 176, 37, 166, 215, 61, 223, 230, 126, 48, 72, 252, 54,
+ 183, 45, 108, 201, 161, 79, 239, 125, 191, 184, 246, 27, 15, 69, 109,
+ 174, 235, 249, 54, 247, 234, 104, 209, 6, 92, 131, 45, 201, 250, 178,
+ 167, 112, 191, 184, 196, 243, 222, 71, 3, 153, 63, 2, 91, 114, 191,
+ 247, 65, 228, 103, 49, 46, 197, 125, 229, 151, 47, 169, 203, 142, 222,
+ 239, 30, 153, 231, 111, 98, 22, 236, 189, 164, 246, 127, 229, 63, 220,
+ 87, 222, 171, 184, 31, 187, 87, 113, 143, 108, 207, 131, 123, 22, 227,
+ 175, 104, 163, 0, 125, 42, 144, 218, 137, 216, 243, 224, 158, 197, 16,
+ 174, 60, 14, 240, 238, 177, 148, 238, 126, 112, 207, 98, 252, 95, 185,
+ 227, 190, 178, 52, 191, 241, 187, 31, 220, 179, 24, 154, 247, 7, 249,
+ 252, 50, 98, 207, 131, 125, 126, 73, 243, 249, 32, 159, 95, 198, 239,
+ 126, 176, 207, 47, 105, 157, 200, 239, 201, 236, 184, 164, 142, 119, 221,
+ 111, 205, 120, 254, 38, 102, 60, 173, 177, 93, 255, 225, 190, 242, 203,
+ 138, 251, 177, 47, 41, 222, 147, 217, 245, 0, 223, 147, 121, 73, 113,
+ 95, 25, 60, 181, 201, 11, 237, 122, 128, 239, 201, 40, 218, 160, 113,
+ 187, 199, 178, 124, 231, 3, 124, 79, 102, 215, 29, 247, 149, 165, 54,
+ 252, 119, 62, 192, 247, 100, 118, 61, 216, 231, 151, 108, 215, 131, 125,
+ 126, 73, 243, 249, 32, 159, 95, 250, 239, 124, 176, 207, 47, 105, 157,
+ 200, 207, 98, 182, 66, 15, 94, 190, 207, 154, 81, 252, 77, 76, 127,
+ 212, 45, 216, 246, 31, 222, 147, 217, 161, 240, 1, 219, 21, 239, 201,
+ 108, 171, 218, 154, 169, 187, 245, 5, 143, 15, 216, 174, 240, 1, 224,
+ 169, 77, 30, 77, 190, 88, 181, 53, 115, 230, 141, 30, 30, 95, 166,
+ 104, 131, 198, 237, 30, 75, 244, 139, 85, 91, 51, 175, 124, 50, 212,
+ 243, 158, 204, 182, 59, 222, 147, 145, 218, 40, 219, 90, 181, 53, 115,
+ 179, 105, 19, 207, 123, 50, 219, 238, 254, 173, 42, 205, 169, 155, 191,
+ 91, 59, 21, 222, 147, 121, 241, 238, 120, 52, 127, 255, 43, 94, 244,
+ 61, 240, 104, 174, 254, 87, 60, 154, 187, 187, 225, 209, 188, 252, 87,
+ 60, 57, 54, 219, 170, 136, 205, 54, 65, 15, 118, 220, 111, 205, 40,
+ 254, 38, 230, 11, 208, 205, 231, 254, 195, 123, 50, 47, 40, 124, 192,
+ 11, 138, 216, 108, 203, 3, 124, 79, 70, 209, 70, 1, 250, 84, 38,
+ 181, 19, 177, 229, 1, 198, 102, 207, 41, 214, 37, 120, 247, 88, 74,
+ 55, 63, 192, 216, 236, 185, 59, 98, 51, 105, 126, 227, 55, 63, 192,
+ 216, 108, 203, 131, 245, 51, 17, 91, 30, 172, 159, 161, 249, 124, 144,
+ 126, 38, 126, 243, 131, 245, 51, 180, 78, 228, 216, 108, 61, 244, 96,
+ 235, 253, 214, 140, 226, 29, 102, 212, 45, 219, 240, 31, 98, 179, 77,
+ 138, 152, 102, 163, 34, 54, 219, 240, 0, 99, 179, 141, 138, 117, 9,
+ 158, 218, 228, 133, 54, 60, 192, 216, 76, 209, 6, 141, 219, 61, 150,
+ 229, 207, 62, 192, 216, 108, 195, 29, 177, 153, 212, 134, 255, 179, 15,
+ 48, 54, 219, 240, 96, 247, 51, 108, 195, 131, 221, 207, 208, 124, 62,
+ 200, 253, 140, 255, 179, 15, 118, 63, 67, 235, 68, 254, 59, 178, 107,
+ 160, 7, 155, 148, 107, 102, 100, 194, 96, 139, 89, 252, 163, 66, 229,
+ 48, 164, 184, 1, 117, 253, 215, 93, 82, 135, 132, 236, 136, 60, 245,
+ 94, 97, 228, 160, 200, 22, 111, 164, 188, 59, 61, 114, 100, 212, 29,
+ 177, 217, 122, 133, 15, 88, 167, 240, 51, 107, 43, 211, 131, 157, 145,
+ 116, 95, 16, 227, 137, 8, 9, 153, 19, 49, 50, 170, 206, 93, 245,
+ 128, 202, 200, 62, 96, 157, 194, 7, 128, 167, 54, 185, 159, 249, 79,
+ 109, 212, 253, 79, 109, 248, 175, 187, 195, 7, 72, 99, 41, 93, 243,
+ 95, 218, 120, 248, 190, 109, 132, 73, 115, 82, 121, 28, 177, 147, 99,
+ 121, 120, 69, 237, 218, 140, 245, 97, 3, 65, 189, 42, 238, 207, 31,
+ 48, 30, 141, 245, 65, 224, 201, 127, 19, 110, 141, 226, 239, 91, 173,
+ 70, 156, 179, 190, 50, 253, 235, 86, 169, 254, 185, 255, 59, 245, 94,
+ 154, 235, 212, 123, 173, 162, 94, 25, 168, 115, 92, 238, 176, 73, 112,
+ 235, 159, 252, 247, 128, 86, 43, 222, 57, 94, 117, 73, 29, 189, 166,
+ 178, 54, 186, 87, 218, 70, 52, 234, 18, 133, 132, 108, 140, 76, 74,
+ 122, 44, 106, 214, 230, 199, 93, 205, 110, 132, 71, 220, 169, 227, 84,
+ 166, 99, 37, 125, 43, 88, 117, 55, 221, 104, 16, 21, 255, 252, 77,
+ 103, 244, 19, 45, 129, 165, 230, 143, 56, 169, 238, 157, 127, 168, 128,
+ 174, 83, 27, 217, 18, 86, 91, 94, 146, 177, 17, 193, 214, 72, 186,
+ 230, 198, 115, 243, 61, 90, 149, 42, 242, 105, 238, 77, 152, 247, 116,
+ 118, 4, 36, 63, 239, 249, 250, 118, 36, 181, 237, 190, 119, 232, 230,
+ 211, 108, 157, 162, 60, 249, 140, 141, 81, 53, 97, 31, 131, 242, 107,
+ 215, 171, 248, 247, 167, 87, 41, 126, 7, 131, 93, 86, 211, 28, 87,
+ 156, 211, 30, 149, 206, 105, 193, 74, 200, 121, 197, 37, 245, 245, 219,
+ 125, 143, 222, 186, 221, 176, 111, 243, 211, 239, 149, 140, 57, 181, 88,
+ 184, 115, 78, 169, 156, 188, 166, 87, 42, 236, 198, 242, 138, 115, 26,
+ 15, 251, 167, 102, 239, 68, 141, 238, 189, 108, 63, 217, 194, 145, 81,
+ 143, 242, 217, 84, 87, 50, 167, 116, 93, 94, 211, 138, 54, 168, 79,
+ 5, 82, 59, 5, 145, 151, 43, 180, 113, 245, 229, 233, 111, 196, 140,
+ 173, 222, 247, 135, 207, 91, 29, 178, 241, 54, 26, 210, 253, 226, 74,
+ 219, 232, 168, 90, 32, 255, 22, 18, 225, 150, 219, 111, 73, 109, 228,
+ 71, 84, 108, 35, 122, 172, 234, 232, 164, 177, 103, 163, 14, 127, 192,
+ 14, 69, 241, 54, 26, 221, 181, 141, 175, 46, 205, 231, 109, 28, 148,
+ 230, 164, 173, 84, 38, 111, 253, 51, 111, 184, 247, 26, 241, 252, 44,
+ 242, 154, 77, 115, 35, 149, 123, 144, 41, 208, 137, 197, 160, 253, 10,
+ 221, 152, 184, 167, 78, 212, 168, 222, 203, 130, 121, 121, 54, 44, 202,
+ 93, 118, 92, 199, 167, 165, 185, 149, 246, 24, 172, 9, 243, 133, 110,
+ 116, 1, 185, 117, 67, 243, 249, 75, 81, 110, 124, 146, 133, 155, 111,
+ 253, 243, 159, 81, 202, 118, 39, 169, 210, 217, 108, 208, 94, 85, 122,
+ 185, 152, 240, 130, 52, 239, 109, 249, 136, 193, 103, 213, 56, 170, 156,
+ 123, 55, 255, 217, 147, 175, 151, 251, 157, 141, 238, 232, 75, 2, 104,
+ 33, 243, 244, 165, 113, 245, 181, 145, 54, 169, 205, 234, 227, 106, 202,
+ 237, 23, 239, 24, 24, 245, 216, 109, 207, 179, 177, 67, 24, 251, 55,
+ 32, 31, 69, 95, 78, 61, 181, 48, 42, 229, 211, 86, 61, 249, 202,
+ 122, 105, 167, 60, 7, 55, 79, 191, 21, 69, 178, 119, 167, 131, 49,
+ 246, 88, 80, 158, 98, 14, 118, 205, 249, 67, 110, 139, 116, 197, 205,
+ 27, 78, 54, 238, 171, 156, 131, 61, 104, 239, 99, 80, 126, 237, 205,
+ 154, 59, 231, 128, 244, 194, 61, 7, 43, 90, 14, 61, 234, 174, 71,
+ 186, 225, 230, 183, 213, 157, 247, 134, 18, 47, 191, 118, 38, 95, 231,
+ 241, 10, 89, 142, 204, 175, 22, 65, 122, 196, 159, 251, 140, 93, 34,
+ 219, 228, 141, 55, 124, 162, 122, 189, 207, 122, 186, 211, 75, 49, 111,
+ 175, 130, 190, 84, 204, 95, 113, 108, 116, 212, 12, 105, 158, 198, 142,
+ 157, 47, 143, 233, 229, 220, 237, 81, 81, 138, 118, 107, 98, 12, 129,
+ 160, 113, 138, 249, 155, 216, 245, 61, 121, 206, 72, 151, 221, 188, 179,
+ 89, 141, 190, 74, 185, 205, 197, 188, 189, 12, 250, 76, 49, 127, 242,
+ 111, 134, 192, 166, 200, 126, 225, 201, 203, 106, 255, 85, 149, 217, 151,
+ 94, 229, 214, 131, 143, 219, 190, 196, 93, 86, 23, 76, 185, 124, 223,
+ 184, 132, 202, 201, 246, 37, 206, 179, 22, 3, 167, 92, 126, 96, 113,
+ 137, 191, 162, 13, 234, 83, 129, 212, 142, 107, 242, 229, 7, 22, 151,
+ 16, 110, 57, 251, 34, 181, 17, 253, 159, 218, 248, 111, 113, 9, 205,
+ 137, 55, 126, 191, 51, 187, 8, 218, 87, 241, 126, 206, 228, 7, 139,
+ 23, 253, 128, 240, 228, 152, 225, 73, 143, 254, 21, 78, 188, 172, 38,
+ 125, 172, 168, 127, 189, 43, 245, 111, 101, 147, 46, 171, 137, 244, 97,
+ 31, 189, 81, 248, 193, 180, 190, 47, 233, 222, 61, 90, 250, 217, 236,
+ 10, 49, 3, 149, 169, 44, 102, 8, 156, 84, 153, 220, 104, 205, 13,
+ 193, 250, 241, 59, 70, 169, 145, 81, 53, 165, 152, 65, 197, 42, 123,
+ 129, 218, 29, 51, 16, 150, 59, 102, 248, 117, 220, 202, 163, 31, 60,
+ 19, 19, 117, 231, 189, 168, 231, 179, 114, 163, 108, 150, 144, 163, 158,
+ 121, 121, 218, 167, 11, 203, 128, 37, 25, 236, 121, 206, 153, 80, 171,
+ 239, 91, 3, 79, 72, 101, 60, 253, 56, 242, 232, 162, 190, 127, 183,
+ 234, 127, 204, 93, 183, 136, 61, 130, 250, 77, 84, 249, 181, 59, 87,
+ 152, 83, 154, 71, 63, 197, 120, 105, 142, 43, 204, 41, 253, 48, 99,
+ 37, 115, 26, 136, 186, 68, 73, 73, 117, 223, 56, 245, 222, 151, 81,
+ 115, 92, 239, 148, 204, 113, 109, 168, 16, 51, 80, 153, 202, 230, 52,
+ 127, 194, 221, 230, 244, 100, 212, 67, 159, 182, 14, 19, 99, 134, 58,
+ 119, 141, 195, 168, 140, 123, 78, 9, 203, 61, 167, 71, 91, 212, 61,
+ 42, 214, 23, 241, 220, 124, 151, 162, 91, 145, 158, 124, 81, 215, 218,
+ 195, 190, 154, 21, 54, 182, 251, 168, 69, 10, 191, 120, 82, 230, 47,
+ 204, 175, 81, 206, 87, 156, 96, 70, 86, 71, 101, 228, 24, 110, 121,
+ 140, 31, 201, 216, 57, 194, 29, 119, 89, 221, 179, 82, 189, 103, 108,
+ 252, 200, 241, 102, 107, 154, 190, 66, 254, 125, 55, 223, 149, 206, 147,
+ 39, 142, 112, 231, 157, 122, 175, 105, 228, 255, 0, 34, 173, 65, 75,
+ 36, 123, 0, 255, 197, 196, 50, 70, 35, 43, 139, 189, 172, 126, 212,
+ 189, 127, 77, 43, 47, 227, 152, 88, 147, 33, 219, 46, 221, 247, 177,
+ 228, 192, 9, 103, 219, 69, 157, 242, 151, 203, 104, 164, 186, 129, 152,
+ 199, 210, 81, 240, 51, 163, 69, 162, 200, 142, 168, 195, 143, 122, 223,
+ 219, 248, 207, 237, 92, 72, 7, 26, 72, 229, 27, 184, 239, 159, 140,
+ 21, 219, 181, 160, 126, 23, 156, 237, 125, 205, 38, 119, 57, 186, 230,
+ 46, 183, 28, 60, 213, 243, 71, 185, 230, 20, 111, 27, 172, 93, 221,
+ 229, 150, 43, 202, 69, 128, 167, 122, 5, 177, 146, 175, 200, 191, 170,
+ 118, 151, 139, 80, 148, 187, 16, 115, 89, 77, 245, 10, 163, 47, 171,
+ 123, 73, 114, 117, 151, 163, 107, 238, 114, 5, 224, 169, 158, 37, 90,
+ 196, 43, 240, 187, 46, 227, 21, 40, 202, 69, 131, 167, 122, 133, 102,
+ 248, 78, 242, 237, 58, 15, 94, 180, 162, 28, 3, 79, 245, 162, 205,
+ 226, 90, 75, 31, 144, 102, 118, 151, 99, 138, 114, 133, 99, 80, 6,
+ 233, 50, 211, 101, 181, 192, 241, 18, 237, 238, 114, 116, 205, 93, 46,
+ 30, 60, 213, 179, 160, 92, 232, 29, 227, 136, 87, 148, 243, 3, 79,
+ 245, 2, 165, 113, 216, 141, 153, 6, 119, 57, 63, 69, 57, 23, 228,
+ 71, 245, 252, 129, 71, 119, 145, 202, 246, 223, 144, 199, 75, 215, 220,
+ 229, 44, 224, 169, 158, 43, 93, 92, 207, 86, 131, 65, 150, 155, 69,
+ 81, 142, 244, 129, 234, 229, 167, 139, 237, 234, 236, 102, 171, 187, 156,
+ 191, 162, 28, 233, 15, 213, 11, 76, 23, 245, 39, 3, 5, 221, 229,
+ 232, 90, 3, 165, 143, 70, 185, 11, 146, 190, 54, 104, 249, 23, 239,
+ 95, 160, 164, 67, 110, 187, 151, 104, 54, 217, 173, 230, 52, 168, 137,
+ 127, 184, 255, 64, 93, 186, 97, 152, 57, 217, 152, 216, 53, 217, 96,
+ 239, 155, 97, 181, 26, 76, 164, 103, 82, 129, 14, 29, 217, 53, 142,
+ 65, 154, 237, 175, 192, 48, 39, 76, 53, 36, 218, 81, 223, 3, 70,
+ 0, 35, 179, 76, 188, 18, 159, 103, 30, 107, 199, 122, 234, 176, 70,
+ 183, 60, 191, 211, 27, 237, 201, 55, 38, 249, 119, 48, 153, 237, 254,
+ 34, 102, 87, 163, 62, 205, 96, 55, 166, 27, 252, 195, 252, 3, 59,
+ 250, 235, 76, 122, 255, 14, 21, 175, 116, 15, 236, 216, 135, 5, 121,
+ 218, 177, 40, 240, 152, 164, 135, 180, 187, 39, 157, 115, 231, 183, 174,
+ 153, 102, 48, 37, 219, 83, 208, 107, 163, 201, 222, 161, 220, 200, 71,
+ 163, 29, 51, 41, 156, 206, 222, 161, 163, 127, 128, 127, 183, 238, 29,
+ 253, 59, 249, 119, 231, 248, 157, 73, 79, 21, 56, 164, 111, 36, 3,
+ 235, 48, 163, 173, 226, 20, 68, 74, 23, 109, 52, 13, 188, 62, 25,
+ 40, 210, 213, 10, 245, 255, 75, 71, 208, 229, 14, 202, 246, 58, 118,
+ 100, 242, 61, 74, 37, 166, 7, 68, 167, 215, 147, 109, 202, 52, 184,
+ 123, 82, 174, 126, 87, 139, 217, 34, 103, 116, 236, 236, 31, 212, 81,
+ 158, 195, 64, 229, 28, 214, 172, 57, 144, 242, 233, 142, 172, 191, 178,
+ 157, 36, 116, 27, 213, 209, 113, 127, 37, 108, 31, 198, 124, 169, 124,
+ 7, 90, 11, 233, 138, 242, 247, 235, 88, 103, 8, 153, 121, 228, 152,
+ 175, 168, 203, 126, 183, 112, 204, 198, 212, 55, 37, 230, 157, 234, 16,
+ 238, 223, 165, 107, 47, 15, 134, 91, 255, 57, 6, 214, 158, 219, 166,
+ 147, 29, 127, 84, 25, 79, 197, 122, 236, 122, 76, 172, 197, 106, 78,
+ 182, 26, 108, 54, 110, 209, 249, 127, 134, 236, 202, 109, 58, 3, 78,
+ 160, 17, 235, 86, 34, 249, 94, 193, 175, 149, 219, 116, 42, 47, 219,
+ 174, 84, 177, 124, 105, 138, 104, 211, 7, 140, 238, 223, 95, 182, 93,
+ 169, 10, 219, 69, 229, 80, 207, 130, 114, 237, 72, 119, 109, 25, 9,
+ 178, 237, 82, 148, 243, 3, 79, 245, 2, 83, 68, 92, 37, 158, 159,
+ 162, 156, 107, 42, 108, 23, 210, 101, 201, 151, 213, 244, 180, 160, 215,
+ 142, 243, 30, 219, 53, 85, 97, 187, 192, 83, 189, 124, 148, 107, 195,
+ 202, 143, 195, 162, 40, 231, 15, 158, 234, 249, 163, 92, 39, 242, 51,
+ 71, 254, 146, 241, 252, 21, 229, 74, 49, 63, 84, 207, 149, 116, 89,
+ 221, 146, 48, 166, 37, 200, 120, 116, 205, 93, 142, 230, 145, 234, 69,
+ 160, 92, 228, 29, 237, 230, 43, 202, 209, 188, 83, 189, 50, 195, 101,
+ 53, 173, 203, 252, 79, 47, 202, 237, 6, 26, 203, 219, 66, 170, 87,
+ 96, 16, 231, 197, 208, 145, 245, 119, 219, 194, 210, 20, 111, 109, 161,
+ 216, 39, 210, 113, 139, 2, 35, 221, 150, 108, 51, 152, 108, 124, 61,
+ 151, 183, 5, 99, 120, 54, 44, 193, 164, 192, 201, 30, 253, 12, 84,
+ 212, 101, 9, 105, 6, 247, 58, 35, 217, 40, 108, 162, 12, 219, 213,
+ 104, 139, 54, 219, 140, 180, 114, 58, 192, 234, 245, 113, 247, 33, 95,
+ 81, 190, 166, 91, 125, 19, 116, 214, 187, 90, 101, 51, 147, 237, 153,
+ 191, 178, 174, 209, 98, 86, 152, 164, 187, 154, 51, 26, 4, 213, 39,
+ 189, 32, 121, 202, 245, 211, 209, 174, 46, 217, 96, 67, 101, 79, 167,
+ 81, 55, 202, 172, 55, 26, 200, 14, 218, 184, 191, 234, 71, 113, 70,
+ 82, 229, 125, 238, 234, 230, 129, 97, 200, 212, 165, 117, 112, 99, 78,
+ 34, 3, 232, 78, 116, 244, 239, 226, 31, 52, 153, 204, 98, 80, 96,
+ 96, 215, 64, 22, 18, 236, 150, 105, 153, 225, 63, 218, 66, 197, 88,
+ 185, 241, 243, 23, 49, 184, 175, 50, 40, 237, 223, 64, 93, 228, 104,
+ 233, 158, 36, 242, 103, 223, 37, 22, 142, 28, 29, 105, 77, 215, 217,
+ 51, 172, 6, 86, 249, 189, 228, 68, 96, 38, 122, 108, 68, 141, 74,
+ 246, 83, 231, 84, 98, 185, 167, 42, 105, 163, 44, 30, 58, 236, 139,
+ 53, 100, 72, 203, 52, 218, 238, 30, 183, 6, 238, 90, 223, 54, 117,
+ 109, 168, 179, 179, 230, 82, 120, 209, 245, 70, 33, 174, 83, 59, 157,
+ 29, 213, 159, 134, 127, 119, 107, 110, 136, 191, 34, 214, 174, 62, 192,
+ 207, 57, 99, 90, 71, 231, 160, 128, 117, 65, 119, 143, 197, 239, 164,
+ 251, 197, 240, 255, 61, 175, 124, 251, 119, 195, 255, 95, 242, 64, 249,
+ 141, 118, 172, 90, 180, 112, 135, 152, 213, 104, 7, 255, 182, 123, 119,
+ 173, 246, 92, 140, 51, 223, 219, 182, 232, 102, 189, 246, 238, 250, 183,
+ 111, 117, 22, 244, 183, 106, 57, 207, 245, 154, 114, 128, 255, 142, 109,
+ 241, 123, 197, 11, 206, 230, 57, 247, 77, 29, 200, 31, 70, 129, 231,
+ 121, 241, 185, 81, 7, 40, 189, 31, 249, 224, 67, 220, 245, 231, 247,
+ 170, 227, 200, 62, 214, 199, 57, 57, 250, 153, 32, 69, 125, 65, 81,
+ 223, 73, 121, 58, 94, 135, 49, 202, 215, 113, 44, 177, 254, 219, 153,
+ 198, 146, 155, 69, 95, 56, 116, 51, 23, 239, 119, 223, 47, 38, 249,
+ 147, 156, 221, 242, 47, 104, 36, 233, 11, 233, 77, 115, 145, 146, 12,
+ 233, 25, 86, 254, 219, 207, 149, 75, 225, 169, 179, 173, 28, 134, 195,
+ 9, 66, 187, 227, 9, 206, 55, 162, 38, 10, 79, 47, 109, 20, 177,
+ 224, 239, 9, 66, 255, 87, 94, 20, 252, 203, 201, 247, 191, 236, 197,
+ 60, 148, 117, 37, 79, 200, 91, 63, 35, 44, 119, 216, 150, 208, 58,
+ 3, 87, 85, 248, 38, 241, 173, 27, 121, 66, 236, 191, 77, 67, 115,
+ 94, 107, 198, 127, 83, 248, 252, 130, 154, 69, 127, 148, 229, 9, 223,
+ 110, 255, 151, 239, 81, 47, 125, 218, 60, 108, 124, 206, 191, 197, 53,
+ 190, 201, 187, 171, 252, 124, 74, 134, 5, 46, 174, 111, 32, 55, 199,
+ 172, 151, 230, 132, 220, 190, 157, 39, 60, 110, 122, 101, 59, 165, 111,
+ 172, 183, 108, 63, 189, 108, 117, 59, 119, 223, 173, 243, 253, 156, 147,
+ 158, 232, 232, 12, 88, 184, 52, 152, 255, 78, 242, 247, 121, 194, 251,
+ 207, 125, 23, 186, 183, 245, 31, 188, 253, 53, 174, 79, 138, 82, 175,
+ 229, 9, 91, 34, 196, 191, 91, 58, 229, 244, 31, 97, 117, 235, 13,
+ 45, 30, 247, 173, 216, 254, 204, 97, 29, 132, 195, 25, 53, 156, 151,
+ 126, 47, 45, 166, 250, 41, 231, 91, 11, 179, 98, 250, 58, 223, 233,
+ 126, 144, 63, 119, 157, 25, 211, 87, 72, 78, 107, 46, 68, 119, 22,
+ 248, 223, 65, 14, 236, 113, 48, 188, 119, 103, 65, 123, 107, 230, 116,
+ 241, 91, 132, 209, 117, 157, 181, 107, 175, 112, 54, 254, 253, 49, 39,
+ 127, 231, 72, 219, 90, 248, 167, 67, 63, 33, 76, 250, 221, 215, 87,
+ 127, 136, 114, 234, 178, 155, 10, 13, 119, 79, 230, 223, 213, 168, 78,
+ 93, 8, 47, 252, 123, 136, 227, 209, 166, 57, 188, 254, 233, 189, 58,
+ 109, 205, 164, 63, 181, 36, 35, 165, 252, 73, 198, 119, 174, 127, 210,
+ 137, 178, 199, 69, 178, 27, 19, 140, 186, 123, 200, 127, 212, 190, 20,
+ 167, 50, 61, 200, 254, 137, 243, 85, 91, 35, 87, 201, 71, 26, 109,
+ 96, 21, 228, 95, 107, 82, 158, 80, 20, 147, 20, 246, 89, 221, 209,
+ 225, 241, 45, 34, 42, 252, 14, 245, 111, 243, 102, 9, 207, 238, 45,
+ 46, 249, 163, 207, 199, 252, 218, 242, 117, 71, 195, 143, 28, 207, 21,
+ 26, 143, 119, 240, 249, 127, 248, 227, 247, 195, 223, 92, 93, 189, 36,
+ 126, 73, 110, 165, 242, 127, 21, 178, 122, 161, 109, 92, 88, 64, 73,
+ 71, 254, 119, 16, 142, 55, 138, 43, 254, 22, 121, 79, 157, 121, 129,
+ 235, 90, 241, 199, 1, 161, 191, 133, 108, 57, 82, 44, 221, 51, 182,
+ 65, 254, 19, 32, 255, 67, 171, 79, 115, 249, 231, 159, 201, 21, 190,
+ 251, 250, 195, 226, 243, 175, 23, 241, 249, 47, 219, 114, 61, 172, 235,
+ 220, 60, 97, 93, 196, 68, 222, 159, 212, 85, 135, 75, 166, 59, 245,
+ 225, 27, 150, 138, 237, 151, 254, 222, 93, 120, 234, 201, 64, 231, 245,
+ 23, 63, 210, 82, 253, 219, 39, 78, 59, 110, 142, 159, 171, 61, 49,
+ 35, 142, 95, 247, 141, 157, 235, 200, 251, 217, 230, 188, 101, 111, 205,
+ 229, 247, 22, 242, 27, 102, 180, 118, 104, 174, 159, 229, 233, 216, 189,
+ 7, 157, 135, 178, 7, 70, 244, 8, 201, 228, 243, 243, 126, 219, 219,
+ 142, 47, 141, 67, 29, 1, 181, 196, 191, 27, 86, 54, 37, 91, 91,
+ 52, 53, 203, 25, 187, 122, 55, 111, 255, 135, 71, 199, 10, 27, 54,
+ 180, 211, 46, 126, 94, 252, 27, 133, 243, 71, 158, 112, 142, 207, 186,
+ 40, 60, 252, 204, 158, 114, 242, 39, 25, 87, 176, 255, 208, 9, 87,
+ 19, 145, 236, 58, 171, 45, 195, 118, 119, 5, 120, 183, 172, 188, 108,
+ 51, 191, 73, 20, 246, 143, 252, 218, 17, 252, 79, 161, 179, 42, 242,
+ 127, 228, 201, 92, 225, 211, 14, 223, 133, 31, 249, 243, 163, 226, 78,
+ 105, 5, 21, 190, 89, 189, 188, 45, 79, 88, 217, 239, 233, 208, 252,
+ 155, 99, 249, 252, 31, 109, 63, 179, 120, 205, 123, 57, 194, 212, 140,
+ 56, 62, 95, 151, 59, 13, 47, 89, 127, 45, 206, 113, 58, 59, 167,
+ 82, 249, 127, 254, 111, 158, 16, 242, 113, 199, 176, 192, 182, 226, 223,
+ 53, 15, 110, 31, 80, 124, 10, 121, 227, 15, 175, 228, 233, 238, 91,
+ 150, 134, 78, 237, 190, 58, 244, 208, 45, 81, 254, 118, 200, 255, 73,
+ 200, 63, 215, 62, 128, 219, 228, 169, 103, 103, 9, 62, 207, 44, 60,
+ 242, 203, 0, 53, 95, 175, 103, 38, 143, 236, 243, 41, 116, 37, 39,
+ 189, 6, 175, 111, 30, 168, 214, 142, 59, 194, 66, 71, 160, 28, 165,
+ 243, 98, 125, 4, 253, 194, 199, 157, 77, 62, 248, 52, 156, 234, 127,
+ 220, 249, 159, 162, 134, 183, 102, 57, 35, 231, 222, 230, 253, 111, 124,
+ 107, 150, 208, 107, 75, 81, 241, 184, 173, 255, 114, 249, 69, 35, 127,
+ 228, 214, 127, 195, 147, 107, 205, 20, 255, 78, 96, 239, 1, 218, 14,
+ 167, 223, 118, 46, 233, 16, 192, 215, 127, 191, 143, 27, 133, 205, 169,
+ 155, 43, 188, 215, 238, 95, 94, 127, 234, 159, 89, 206, 233, 77, 247,
+ 21, 23, 53, 201, 21, 191, 171, 251, 33, 87, 251, 231, 197, 43, 37,
+ 89, 183, 197, 111, 117, 246, 236, 141, 117, 198, 214, 154, 234, 140, 30,
+ 188, 180, 156, 252, 73, 198, 21, 214, 255, 227, 158, 184, 33, 221, 96,
+ 215, 221, 75, 7, 198, 76, 31, 95, 206, 54, 135, 60, 187, 175, 232,
+ 106, 114, 154, 112, 173, 112, 227, 225, 170, 200, 63, 246, 143, 60, 225,
+ 192, 183, 142, 176, 159, 230, 158, 61, 242, 244, 250, 205, 21, 254, 246,
+ 252, 98, 216, 127, 237, 185, 230, 197, 91, 142, 61, 201, 117, 227, 227,
+ 46, 77, 195, 62, 120, 53, 79, 248, 237, 7, 45, 159, 143, 207, 90,
+ 79, 47, 218, 229, 212, 150, 164, 30, 174, 220, 254, 175, 2, 126, 135,
+ 178, 162, 176, 173, 143, 28, 231, 216, 171, 125, 138, 139, 179, 254, 204,
+ 19, 222, 60, 216, 139, 167, 63, 251, 245, 104, 232, 143, 7, 34, 67,
+ 151, 42, 228, 63, 25, 242, 143, 121, 242, 5, 46, 127, 225, 209, 153,
+ 66, 167, 201, 47, 21, 13, 153, 28, 204, 229, 63, 122, 194, 142, 208,
+ 166, 144, 191, 186, 78, 62, 255, 219, 214, 53, 167, 4, 107, 223, 250,
+ 119, 93, 175, 230, 13, 69, 249, 189, 122, 235, 71, 237, 135, 73, 205,
+ 157, 154, 109, 245, 74, 168, 126, 157, 78, 147, 138, 223, 184, 62, 203,
+ 185, 59, 70, 148, 255, 209, 235, 179, 132, 126, 97, 103, 139, 127, 188,
+ 122, 141, 203, 255, 125, 228, 159, 186, 122, 45, 252, 237, 250, 98, 253,
+ 29, 13, 67, 180, 7, 79, 142, 114, 77, 13, 20, 229, 111, 99, 113,
+ 97, 181, 110, 207, 18, 52, 61, 111, 137, 223, 223, 23, 218, 157, 155,
+ 126, 113, 21, 31, 243, 21, 191, 213, 28, 56, 113, 173, 54, 171, 221,
+ 191, 37, 191, 21, 138, 223, 88, 69, 47, 110, 225, 10, 180, 219, 156,
+ 173, 6, 191, 89, 78, 254, 228, 243, 101, 255, 143, 120, 143, 108, 63,
+ 249, 255, 252, 71, 69, 74, 203, 72, 71, 148, 124, 119, 233, 149, 212,
+ 83, 239, 223, 51, 254, 160, 176, 114, 197, 51, 206, 153, 191, 6, 29,
+ 200, 107, 60, 34, 98, 241, 212, 83, 66, 88, 244, 187, 7, 170, 226,
+ 255, 87, 118, 158, 42, 124, 25, 215, 36, 120, 193, 184, 25, 129, 127,
+ 127, 253, 190, 227, 206, 90, 213, 83, 59, 11, 63, 246, 9, 119, 246,
+ 220, 211, 152, 63, 195, 5, 47, 80, 222, 188, 191, 159, 230, 207, 122,
+ 89, 146, 99, 95, 243, 109, 43, 247, 223, 43, 126, 171, 138, 255, 175,
+ 38, 181, 255, 113, 168, 150, 199, 107, 63, 160, 125, 202, 91, 60, 198,
+ 143, 167, 55, 189, 63, 53, 228, 231, 109, 93, 228, 246, 143, 109, 174,
+ 237, 124, 111, 167, 221, 241, 89, 255, 65, 60, 239, 37, 75, 77, 33,
+ 228, 250, 120, 231, 230, 106, 223, 240, 254, 6, 95, 31, 207, 243, 28,
+ 189, 135, 240, 250, 43, 144, 239, 236, 61, 68, 142, 255, 190, 14, 95,
+ 237, 252, 66, 55, 207, 153, 241, 115, 79, 158, 183, 188, 199, 76, 33,
+ 105, 250, 19, 218, 41, 111, 126, 199, 199, 15, 222, 65, 121, 95, 108,
+ 94, 202, 227, 63, 87, 35, 255, 144, 87, 63, 153, 45, 199, 127, 35,
+ 62, 255, 72, 27, 109, 202, 21, 126, 202, 157, 93, 46, 254, 35, 25,
+ 223, 185, 254, 73, 39, 226, 31, 193, 158, 184, 37, 236, 127, 138, 217,
+ 170, 203, 190, 187, 244, 156, 198, 191, 130, 149, 233, 182, 157, 71, 185,
+ 242, 190, 31, 37, 36, 58, 84, 221, 170, 178, 254, 247, 27, 115, 133,
+ 143, 191, 53, 5, 182, 60, 250, 217, 62, 195, 254, 31, 42, 248, 255,
+ 15, 95, 206, 17, 52, 131, 19, 28, 66, 227, 24, 241, 217, 254, 224,
+ 4, 45, 229, 253, 213, 104, 60, 223, 95, 92, 41, 154, 184, 223, 47,
+ 105, 255, 222, 123, 201, 191, 237, 158, 181, 251, 191, 217, 247, 12, 151,
+ 255, 51, 127, 157, 15, 185, 5, 249, 151, 188, 60, 142, 199, 243, 7,
+ 223, 89, 221, 62, 99, 211, 79, 219, 220, 245, 237, 119, 200, 127, 215,
+ 158, 27, 218, 144, 29, 83, 156, 95, 204, 24, 207, 229, 21, 188, 99,
+ 138, 176, 3, 121, 143, 221, 28, 198, 211, 175, 69, 47, 13, 105, 156,
+ 191, 91, 150, 127, 55, 253, 81, 231, 130, 103, 91, 151, 172, 47, 88,
+ 201, 235, 151, 212, 10, 116, 62, 246, 85, 111, 103, 151, 199, 167, 112,
+ 121, 53, 249, 170, 55, 207, 251, 163, 145, 147, 203, 179, 3, 242, 47,
+ 53, 114, 6, 187, 235, 127, 174, 95, 234, 234, 49, 244, 185, 240, 131,
+ 97, 237, 185, 252, 23, 45, 92, 163, 93, 112, 198, 46, 212, 206, 154,
+ 44, 198, 255, 103, 236, 78, 202, 91, 59, 253, 77, 158, 238, 188, 114,
+ 99, 200, 191, 131, 183, 202, 242, 63, 211, 178, 129, 163, 125, 215, 121,
+ 17, 227, 132, 241, 221, 148, 242, 39, 57, 187, 229, 239, 234, 40, 218,
+ 125, 210, 137, 136, 122, 34, 233, 236, 105, 186, 123, 108, 255, 216, 83,
+ 155, 26, 29, 80, 166, 187, 12, 91, 44, 52, 125, 183, 179, 179, 253,
+ 137, 54, 251, 171, 34, 255, 146, 183, 146, 133, 192, 234, 170, 160, 245,
+ 151, 158, 219, 31, 158, 80, 241, 239, 101, 183, 63, 216, 90, 136, 252,
+ 176, 159, 144, 180, 187, 17, 31, 47, 120, 103, 7, 228, 229, 71, 140,
+ 229, 243, 103, 186, 94, 243, 64, 89, 141, 109, 247, 92, 255, 243, 158,
+ 154, 127, 32, 105, 72, 14, 223, 175, 253, 118, 244, 26, 151, 255, 180,
+ 35, 121, 92, 254, 143, 143, 89, 214, 254, 177, 160, 239, 183, 187, 235,
+ 103, 72, 246, 223, 45, 255, 224, 171, 51, 132, 53, 55, 187, 57, 222,
+ 188, 50, 128, 183, 183, 238, 102, 55, 109, 8, 242, 22, 22, 205, 221,
+ 71, 233, 15, 150, 143, 12, 62, 19, 122, 49, 80, 126, 111, 229, 208,
+ 111, 194, 194, 183, 163, 35, 150, 111, 28, 192, 231, 191, 218, 202, 233,
+ 194, 198, 183, 70, 57, 90, 14, 12, 226, 250, 10, 94, 75, 121, 125,
+ 30, 58, 195, 241, 26, 15, 8, 10, 138, 124, 232, 140, 44, 255, 190,
+ 79, 190, 24, 177, 167, 186, 143, 235, 250, 121, 235, 65, 254, 27, 103,
+ 63, 229, 9, 199, 159, 253, 61, 108, 105, 245, 54, 188, 252, 158, 103,
+ 127, 47, 110, 129, 188, 203, 23, 222, 230, 235, 97, 196, 188, 39, 130,
+ 243, 102, 191, 37, 143, 63, 108, 246, 120, 87, 183, 221, 219, 34, 102,
+ 173, 168, 209, 93, 41, 127, 146, 241, 157, 235, 159, 116, 130, 117, 133,
+ 47, 232, 116, 89, 157, 104, 213, 153, 140, 25, 233, 119, 149, 222, 199,
+ 95, 110, 47, 183, 254, 87, 92, 171, 235, 154, 122, 161, 141, 163, 81,
+ 204, 233, 144, 160, 42, 200, 191, 65, 96, 174, 240, 237, 41, 159, 32,
+ 117, 215, 87, 246, 173, 139, 248, 187, 194, 250, 255, 225, 68, 182, 112,
+ 124, 254, 52, 199, 240, 135, 219, 242, 246, 193, 107, 41, 111, 83, 248,
+ 30, 222, 108, 234, 39, 221, 246, 63, 123, 173, 219, 190, 123, 201, 255,
+ 236, 69, 159, 131, 61, 95, 81, 117, 224, 254, 243, 171, 91, 92, 254,
+ 57, 230, 28, 46, 255, 14, 215, 78, 181, 27, 21, 249, 240, 54, 165,
+ 252, 167, 64, 254, 237, 37, 249, 251, 6, 78, 21, 6, 190, 255, 190,
+ 99, 97, 193, 87, 124, 254, 7, 191, 255, 190, 182, 6, 242, 22, 12,
+ 136, 230, 233, 254, 63, 254, 29, 60, 224, 157, 126, 178, 252, 141, 49,
+ 105, 194, 213, 205, 190, 17, 99, 206, 104, 184, 252, 227, 119, 46, 118,
+ 76, 109, 151, 233, 28, 58, 74, 199, 245, 23, 188, 160, 67, 222, 47,
+ 255, 116, 228, 235, 169, 43, 242, 235, 95, 234, 40, 219, 255, 228, 220,
+ 116, 215, 75, 189, 55, 185, 244, 225, 111, 242, 188, 63, 38, 212, 214,
+ 62, 181, 102, 150, 176, 117, 233, 112, 94, 31, 188, 243, 119, 228, 77,
+ 12, 88, 193, 211, 19, 95, 125, 42, 228, 81, 163, 77, 94, 255, 221,
+ 191, 153, 224, 250, 233, 179, 247, 35, 234, 236, 243, 43, 39, 127, 146,
+ 179, 91, 254, 36, 111, 254, 96, 179, 158, 39, 254, 51, 232, 238, 181,
+ 251, 135, 93, 58, 107, 117, 142, 239, 151, 42, 248, 133, 62, 234, 26,
+ 54, 113, 154, 246, 242, 51, 231, 132, 13, 213, 159, 117, 77, 157, 60,
+ 188, 74, 251, 127, 253, 190, 9, 130, 163, 251, 92, 173, 235, 72, 92,
+ 88, 239, 173, 191, 87, 88, 255, 29, 227, 27, 8, 45, 198, 14, 22,
+ 222, 95, 57, 145, 95, 59, 126, 184, 191, 179, 120, 23, 98, 172, 168,
+ 95, 120, 122, 90, 189, 167, 181, 95, 78, 251, 194, 113, 250, 216, 228,
+ 74, 229, 79, 190, 222, 241, 250, 207, 7, 146, 230, 95, 228, 235, 191,
+ 52, 183, 54, 151, 255, 63, 239, 214, 221, 201, 159, 81, 175, 63, 187,
+ 61, 186, 197, 107, 173, 220, 125, 207, 148, 226, 255, 118, 146, 252, 135,
+ 180, 15, 22, 186, 133, 191, 167, 205, 252, 70, 252, 221, 133, 191, 67,
+ 46, 58, 182, 172, 209, 9, 218, 113, 173, 74, 196, 87, 163, 31, 114,
+ 198, 254, 246, 148, 35, 189, 241, 112, 209, 254, 206, 243, 143, 232, 209,
+ 184, 44, 98, 212, 154, 212, 8, 170, 191, 239, 100, 83, 225, 208, 250,
+ 65, 194, 178, 154, 103, 120, 249, 215, 215, 15, 114, 30, 89, 241, 168,
+ 16, 17, 23, 203, 99, 157, 213, 200, 143, 140, 139, 213, 214, 122, 59,
+ 155, 215, 95, 180, 241, 104, 68, 151, 209, 93, 35, 6, 60, 218, 219,
+ 65, 245, 59, 52, 157, 40, 156, 248, 250, 140, 227, 131, 1, 5, 124,
+ 188, 113, 253, 90, 104, 95, 105, 52, 64, 40, 12, 18, 255, 22, 251,
+ 200, 75, 183, 29, 115, 254, 248, 203, 177, 126, 134, 248, 219, 38, 193,
+ 215, 135, 186, 218, 174, 58, 27, 97, 131, 140, 202, 237, 255, 58, 221,
+ 177, 254, 187, 138, 118, 95, 41, 127, 254, 117, 193, 93, 164, 183, 240,
+ 172, 85, 24, 35, 201, 191, 197, 196, 105, 142, 127, 32, 255, 141, 144,
+ 127, 167, 201, 195, 157, 85, 145, 255, 218, 135, 210, 132, 86, 101, 103,
+ 74, 142, 95, 111, 81, 210, 240, 72, 73, 5, 249, 255, 242, 91, 47,
+ 97, 110, 141, 32, 129, 125, 83, 196, 227, 245, 1, 103, 58, 59, 111,
+ 213, 237, 38, 108, 62, 150, 200, 231, 175, 40, 190, 137, 35, 121, 70,
+ 7, 109, 208, 154, 156, 255, 23, 249, 159, 242, 77, 17, 54, 140, 217,
+ 168, 93, 182, 120, 45, 111, 239, 235, 126, 91, 29, 251, 158, 183, 10,
+ 134, 79, 183, 243, 254, 204, 254, 105, 137, 118, 222, 140, 183, 195, 47,
+ 238, 17, 127, 239, 224, 243, 118, 195, 35, 142, 245, 63, 17, 241, 221,
+ 236, 175, 156, 110, 249, 67, 230, 66, 147, 154, 103, 194, 221, 242, 119,
+ 66, 254, 117, 33, 115, 73, 254, 225, 127, 79, 137, 117, 60, 44, 201,
+ 127, 161, 36, 255, 160, 6, 189, 185, 252, 108, 51, 199, 10, 223, 159,
+ 171, 229, 156, 230, 183, 137, 235, 143, 61, 242, 79, 237, 207, 67, 250,
+ 11, 195, 126, 252, 134, 247, 231, 237, 159, 214, 105, 83, 15, 239, 208,
+ 134, 189, 40, 254, 29, 245, 16, 73, 254, 87, 39, 76, 115, 148, 219,
+ 255, 117, 244, 200, 159, 226, 61, 178, 253, 228, 255, 11, 218, 139, 148,
+ 146, 145, 110, 176, 222, 227, 6, 192, 243, 75, 155, 105, 219, 212, 140,
+ 208, 126, 54, 251, 140, 227, 215, 69, 42, 33, 254, 212, 10, 103, 173,
+ 183, 222, 114, 54, 94, 212, 176, 74, 235, 255, 221, 14, 121, 194, 163,
+ 143, 116, 9, 63, 243, 73, 215, 146, 250, 182, 41, 21, 190, 77, 216,
+ 176, 116, 150, 240, 121, 204, 153, 240, 86, 187, 14, 241, 107, 67, 30,
+ 255, 169, 36, 113, 213, 44, 225, 140, 90, 252, 61, 180, 181, 95, 189,
+ 88, 50, 142, 189, 86, 210, 185, 125, 238, 255, 139, 255, 31, 16, 215,
+ 64, 88, 116, 100, 164, 51, 237, 134, 248, 183, 129, 198, 78, 142, 22,
+ 206, 235, 235, 11, 62, 215, 63, 228, 242, 184, 181, 189, 77, 248, 57,
+ 223, 43, 225, 109, 206, 137, 251, 127, 219, 95, 249, 206, 122, 199, 223,
+ 10, 79, 109, 92, 139, 183, 93, 237, 246, 59, 37, 127, 233, 115, 5,
+ 237, 195, 49, 188, 252, 69, 125, 174, 115, 217, 205, 15, 74, 86, 188,
+ 46, 240, 180, 6, 249, 167, 95, 23, 194, 159, 136, 23, 247, 159, 253,
+ 78, 36, 8, 231, 114, 95, 142, 24, 155, 213, 131, 235, 79, 205, 97,
+ 83, 156, 218, 171, 55, 28, 219, 236, 226, 223, 169, 9, 155, 119, 83,
+ 251, 240, 231, 147, 156, 53, 14, 85, 231, 250, 99, 76, 249, 169, 248,
+ 213, 143, 30, 210, 86, 91, 40, 182, 255, 246, 164, 62, 174, 134, 121,
+ 59, 34, 46, 44, 82, 149, 223, 255, 181, 175, 232, 255, 73, 39, 242,
+ 219, 138, 36, 255, 233, 191, 187, 72, 239, 155, 243, 189, 202, 173, 205,
+ 167, 223, 93, 34, 124, 121, 125, 155, 243, 165, 182, 230, 226, 170, 196,
+ 127, 113, 65, 86, 225, 151, 220, 212, 18, 77, 233, 185, 34, 207, 223,
+ 22, 245, 252, 231, 251, 207, 80, 33, 118, 211, 99, 194, 174, 176, 98,
+ 126, 255, 53, 237, 137, 199, 156, 155, 6, 15, 17, 190, 233, 243, 43,
+ 159, 191, 153, 173, 71, 148, 252, 56, 233, 147, 240, 31, 6, 86, 46,
+ 255, 193, 123, 243, 132, 179, 154, 161, 37, 87, 122, 55, 224, 247, 15,
+ 14, 223, 28, 18, 30, 134, 188, 165, 19, 58, 243, 116, 155, 181, 77,
+ 139, 122, 191, 211, 166, 104, 243, 237, 242, 247, 127, 154, 117, 152, 207,
+ 253, 239, 129, 134, 25, 194, 128, 177, 171, 28, 131, 227, 223, 227, 247,
+ 27, 99, 102, 172, 210, 14, 251, 118, 154, 112, 234, 84, 11, 190, 254,
+ 222, 61, 249, 74, 216, 141, 9, 254, 218, 196, 147, 226, 254, 125, 123,
+ 181, 233, 66, 204, 107, 197, 130, 240, 227, 215, 124, 253, 38, 159, 172,
+ 227, 220, 120, 114, 148, 243, 234, 149, 134, 188, 60, 120, 161, 245, 228,
+ 122, 206, 129, 97, 226, 119, 61, 223, 35, 127, 107, 216, 115, 37, 145,
+ 169, 98, 253, 239, 198, 244, 116, 125, 58, 236, 33, 215, 187, 87, 215,
+ 115, 249, 191, 17, 186, 222, 145, 219, 216, 40, 12, 104, 184, 138, 215,
+ 95, 222, 218, 230, 60, 214, 181, 192, 241, 237, 141, 218, 124, 62, 158,
+ 110, 118, 178, 164, 87, 226, 34, 237, 185, 96, 241, 254, 207, 224, 143,
+ 213, 174, 55, 246, 154, 34, 134, 44, 13, 43, 39, 127, 146, 113, 133,
+ 253, 31, 116, 34, 190, 181, 72, 137, 58, 171, 229, 94, 247, 255, 22,
+ 213, 74, 40, 247, 55, 253, 74, 130, 190, 42, 73, 77, 154, 44, 236,
+ 122, 101, 93, 81, 85, 228, 159, 154, 169, 19, 90, 255, 88, 219, 113,
+ 99, 196, 172, 146, 53, 223, 253, 84, 65, 254, 53, 62, 110, 40, 124,
+ 87, 58, 66, 248, 108, 158, 153, 183, 63, 250, 177, 1, 206, 26, 141,
+ 31, 22, 22, 205, 93, 207, 231, 163, 186, 159, 201, 177, 125, 184, 160,
+ 77, 157, 96, 175, 84, 254, 191, 221, 202, 19, 78, 207, 254, 179, 79,
+ 235, 81, 7, 185, 188, 63, 252, 229, 183, 35, 203, 144, 247, 221, 199,
+ 165, 220, 126, 63, 180, 239, 96, 209, 149, 167, 74, 67, 247, 222, 204,
+ 147, 215, 63, 237, 255, 38, 249, 110, 230, 235, 127, 238, 182, 1, 194,
+ 236, 204, 150, 194, 249, 159, 235, 115, 249, 191, 100, 110, 233, 28, 191,
+ 115, 128, 240, 183, 185, 63, 239, 207, 67, 243, 76, 197, 135, 250, 90,
+ 67, 55, 95, 117, 235, 207, 54, 237, 249, 157, 199, 34, 86, 175, 45,
+ 224, 242, 143, 107, 216, 222, 153, 51, 83, 235, 60, 236, 91, 159, 247,
+ 55, 123, 166, 86, 56, 29, 22, 224, 236, 149, 43, 254, 190, 228, 243,
+ 200, 223, 156, 59, 167, 100, 249, 231, 162, 252, 173, 51, 198, 186, 182,
+ 47, 156, 226, 186, 249, 236, 26, 46, 255, 157, 218, 28, 167, 16, 220,
+ 81, 251, 72, 96, 75, 94, 127, 199, 55, 254, 142, 219, 35, 102, 58,
+ 7, 21, 229, 115, 253, 223, 157, 215, 209, 241, 176, 238, 209, 18, 215,
+ 80, 177, 254, 197, 188, 169, 174, 105, 11, 135, 69, 216, 222, 235, 85,
+ 78, 254, 36, 227, 59, 229, 79, 58, 161, 188, 255, 119, 47, 29, 48,
+ 15, 105, 85, 46, 54, 111, 38, 172, 211, 94, 57, 244, 169, 54, 243,
+ 183, 86, 225, 85, 145, 255, 208, 244, 56, 97, 254, 38, 75, 201, 198,
+ 73, 133, 197, 197, 223, 92, 169, 32, 255, 236, 99, 190, 194, 134, 235,
+ 177, 194, 210, 199, 182, 240, 249, 110, 180, 119, 188, 243, 92, 104, 117,
+ 97, 254, 222, 27, 188, 63, 71, 166, 189, 81, 178, 121, 196, 142, 240,
+ 75, 183, 102, 85, 42, 255, 244, 75, 121, 194, 51, 126, 179, 194, 14,
+ 165, 54, 228, 242, 27, 53, 104, 102, 241, 232, 43, 121, 66, 219, 218,
+ 187, 185, 252, 183, 30, 105, 84, 252, 100, 226, 142, 208, 241, 55, 242,
+ 100, 255, 79, 242, 79, 110, 178, 147, 203, 127, 195, 19, 213, 29, 147,
+ 215, 205, 18, 84, 133, 226, 239, 252, 249, 174, 152, 229, 212, 135, 251,
+ 56, 246, 86, 143, 226, 237, 255, 58, 170, 83, 73, 220, 170, 222, 37,
+ 131, 231, 136, 245, 55, 60, 182, 209, 53, 242, 179, 235, 17, 93, 234,
+ 254, 197, 229, 223, 102, 255, 215, 37, 175, 255, 51, 203, 121, 113, 222,
+ 92, 94, 254, 240, 63, 179, 132, 78, 230, 159, 74, 34, 34, 211, 57,
+ 222, 5, 228, 15, 139, 76, 47, 137, 171, 33, 233, 207, 165, 25, 14,
+ 199, 234, 125, 174, 175, 98, 195, 185, 252, 15, 246, 204, 114, 110, 190,
+ 145, 238, 112, 245, 253, 131, 215, 255, 176, 87, 142, 246, 187, 192, 44,
+ 103, 108, 81, 17, 79, 107, 179, 95, 47, 153, 81, 243, 124, 201, 239,
+ 129, 226, 248, 219, 246, 181, 185, 236, 203, 31, 141, 24, 115, 34, 160,
+ 156, 252, 201, 231, 43, 229, 207, 109, 63, 252, 63, 171, 43, 146, 219,
+ 255, 223, 45, 6, 12, 92, 218, 204, 209, 14, 254, 255, 75, 248, 255,
+ 111, 23, 169, 156, 211, 225, 255, 175, 158, 120, 203, 121, 125, 97, 195,
+ 42, 197, 127, 111, 189, 158, 43, 188, 235, 95, 86, 124, 114, 113, 181,
+ 162, 63, 67, 222, 172, 176, 255, 203, 30, 54, 67, 216, 221, 180, 175,
+ 99, 109, 76, 99, 46, 191, 214, 227, 251, 106, 127, 249, 125, 186, 240,
+ 166, 113, 50, 47, 251, 227, 178, 141, 125, 54, 108, 138, 15, 143, 221,
+ 156, 247, 255, 226, 255, 19, 14, 63, 175, 221, 247, 156, 213, 25, 61,
+ 169, 39, 111, 239, 157, 247, 172, 194, 138, 118, 47, 104, 125, 30, 142,
+ 225, 250, 184, 163, 224, 179, 176, 30, 29, 154, 149, 148, 74, 247, 159,
+ 215, 143, 106, 237, 10, 142, 74, 114, 148, 254, 22, 199, 227, 175, 193,
+ 236, 221, 146, 63, 224, 255, 247, 213, 141, 225, 242, 254, 19, 254, 255,
+ 244, 173, 15, 74, 246, 189, 46, 254, 214, 104, 208, 195, 49, 225, 109,
+ 16, 11, 184, 253, 255, 212, 227, 9, 194, 69, 248, 255, 71, 178, 122,
+ 240, 190, 215, 184, 152, 237, 220, 253, 152, 222, 113, 114, 188, 248, 155,
+ 178, 195, 103, 79, 214, 142, 41, 203, 118, 118, 237, 116, 152, 247, 103,
+ 152, 121, 127, 120, 237, 185, 171, 75, 86, 79, 200, 45, 231, 255, 63,
+ 133, 140, 202, 237, 255, 234, 86, 92, 255, 164, 19, 101, 181, 68, 242,
+ 124, 94, 92, 185, 244, 126, 56, 223, 171, 220, 189, 217, 121, 240, 255,
+ 191, 193, 255, 191, 208, 198, 28, 86, 149, 245, 79, 191, 49, 64, 191,
+ 171, 64, 191, 133, 176, 71, 254, 253, 2, 197, 254, 47, 236, 25, 199,
+ 173, 173, 25, 194, 51, 123, 215, 240, 241, 183, 211, 88, 157, 246, 29,
+ 203, 28, 183, 124, 3, 184, 173, 136, 110, 215, 75, 251, 79, 179, 55,
+ 139, 115, 92, 51, 42, 149, 127, 14, 124, 253, 190, 189, 67, 74, 138,
+ 63, 13, 228, 235, 253, 88, 225, 144, 240, 125, 200, 235, 21, 250, 60,
+ 127, 9, 254, 155, 130, 39, 66, 187, 213, 254, 229, 245, 163, 119, 248,
+ 255, 230, 87, 231, 114, 255, 255, 254, 135, 163, 132, 184, 106, 245, 132,
+ 38, 250, 189, 188, 253, 147, 49, 245, 157, 41, 171, 71, 9, 173, 84,
+ 9, 60, 109, 110, 219, 162, 36, 242, 91, 87, 137, 207, 203, 226, 252,
+ 127, 60, 110, 174, 176, 117, 198, 178, 136, 192, 143, 252, 249, 250, 15,
+ 135, 255, 63, 12, 255, 127, 252, 74, 67, 222, 95, 240, 194, 213, 39,
+ 235, 57, 11, 224, 243, 249, 243, 7, 228, 79, 68, 44, 16, 37, 249,
+ 255, 195, 240, 255, 53, 134, 63, 228, 218, 113, 117, 61, 159, 31, 223,
+ 181, 233, 206, 88, 199, 94, 109, 171, 223, 31, 225, 245, 181, 194, 1,
+ 71, 187, 195, 102, 231, 228, 139, 199, 185, 254, 189, 173, 81, 107, 19,
+ 114, 215, 148, 76, 8, 23, 215, 255, 166, 38, 173, 92, 198, 171, 186,
+ 136, 172, 239, 58, 150, 147, 63, 201, 184, 194, 243, 63, 232, 132, 171,
+ 166, 72, 146, 237, 191, 171, 6, 188, 241, 80, 66, 185, 223, 248, 60,
+ 6, 255, 63, 13, 254, 63, 106, 239, 186, 208, 170, 200, 127, 78, 74,
+ 158, 48, 170, 254, 229, 176, 236, 232, 99, 71, 154, 172, 207, 169, 16,
+ 255, 107, 154, 228, 10, 89, 159, 92, 13, 183, 39, 126, 206, 253, 247,
+ 216, 144, 107, 37, 15, 109, 157, 37, 12, 60, 106, 231, 101, 179, 187,
+ 117, 235, 211, 82, 200, 44, 177, 46, 172, 124, 253, 239, 129, 175, 255,
+ 125, 73, 73, 159, 152, 132, 119, 184, 252, 155, 156, 124, 237, 200, 115,
+ 240, 245, 135, 254, 173, 193, 199, 51, 244, 196, 59, 161, 191, 159, 169,
+ 81, 108, 187, 225, 121, 254, 75, 235, 127, 89, 207, 5, 92, 254, 198,
+ 213, 225, 194, 165, 57, 157, 132, 214, 22, 241, 249, 227, 222, 191, 59,
+ 57, 63, 156, 31, 46, 52, 123, 237, 11, 94, 255, 197, 167, 118, 21,
+ 151, 196, 198, 151, 172, 88, 38, 214, 15, 233, 219, 69, 72, 101, 207,
+ 71, 212, 46, 91, 212, 155, 234, 247, 134, 255, 223, 8, 255, 191, 202,
+ 183, 62, 151, 31, 120, 225, 37, 248, 255, 2, 248, 124, 30, 131, 33,
+ 95, 143, 88, 96, 153, 228, 255, 135, 195, 255, 127, 7, 255, 95, 246,
+ 236, 26, 62, 63, 61, 45, 51, 157, 51, 119, 125, 22, 62, 127, 168,
+ 134, 215, 79, 202, 250, 172, 68, 181, 44, 215, 217, 242, 214, 21, 62,
+ 31, 1, 241, 26, 109, 143, 133, 111, 21, 117, 254, 78, 148, 191, 49,
+ 122, 144, 235, 214, 156, 43, 66, 164, 169, 91, 57, 249, 147, 140, 43,
+ 60, 255, 171, 85, 169, 255, 175, 84, 7, 94, 30, 210, 170, 156, 108,
+ 90, 194, 255, 255, 9, 255, 63, 250, 183, 86, 37, 85, 145, 127, 226,
+ 249, 4, 33, 187, 231, 248, 240, 210, 35, 89, 97, 187, 135, 156, 173,
+ 224, 255, 255, 114, 61, 34, 60, 114, 35, 90, 40, 85, 23, 242, 249,
+ 254, 160, 83, 180, 179, 78, 70, 125, 33, 90, 251, 37, 239, 207, 205,
+ 83, 207, 134, 251, 143, 126, 161, 164, 115, 118, 229, 241, 127, 236, 229,
+ 60, 97, 248, 134, 252, 176, 208, 137, 63, 112, 249, 127, 197, 242, 139,
+ 227, 254, 65, 222, 71, 157, 56, 222, 95, 7, 127, 13, 245, 173, 22,
+ 80, 252, 254, 245, 60, 249, 249, 15, 201, 191, 218, 204, 149, 92, 254,
+ 157, 51, 85, 142, 197, 191, 204, 18, 150, 46, 90, 201, 203, 31, 62,
+ 55, 203, 121, 243, 37, 149, 163, 227, 167, 93, 120, 250, 181, 249, 163,
+ 194, 34, 39, 207, 43, 62, 125, 81, 172, 255, 113, 235, 5, 46, 215,
+ 75, 31, 70, 76, 104, 55, 72, 180, 255, 133, 95, 151, 56, 224, 255,
+ 223, 157, 55, 151, 247, 215, 9, 255, 223, 47, 253, 167, 146, 169, 240,
+ 249, 60, 222, 71, 126, 119, 196, 2, 9, 146, 255, 63, 113, 97, 134,
+ 227, 93, 248, 255, 67, 177, 225, 124, 126, 214, 117, 205, 118, 214, 217,
+ 105, 118, 148, 54, 92, 203, 235, 143, 186, 106, 213, 118, 153, 149, 237,
+ 12, 217, 222, 130, 167, 75, 84, 185, 225, 155, 110, 235, 194, 63, 105,
+ 38, 214, 223, 218, 125, 132, 75, 181, 110, 129, 112, 187, 36, 184, 156,
+ 252, 233, 153, 159, 82, 254, 252, 29, 32, 122, 254, 87, 77, 36, 241,
+ 253, 159, 187, 59, 128, 220, 179, 173, 180, 19, 15, 39, 8, 141, 142,
+ 39, 56, 157, 81, 19, 157, 179, 150, 54, 138, 120, 230, 239, 9, 194,
+ 176, 87, 94, 172, 146, 255, 255, 25, 242, 105, 145, 250, 84, 241, 182,
+ 191, 119, 21, 253, 62, 101, 121, 133, 247, 127, 70, 97, 93, 182, 105,
+ 244, 120, 232, 11, 147, 58, 242, 249, 78, 221, 84, 173, 168, 229, 183,
+ 121, 66, 190, 85, 197, 231, 111, 101, 94, 64, 241, 162, 137, 170, 240,
+ 99, 95, 254, 255, 188, 255, 83, 92, 150, 39, 188, 51, 246, 151, 208,
+ 113, 99, 196, 223, 154, 126, 237, 198, 23, 69, 163, 175, 229, 9, 62,
+ 187, 71, 112, 251, 187, 199, 247, 74, 241, 175, 3, 135, 134, 181, 251,
+ 90, 108, 127, 112, 163, 14, 194, 94, 115, 13, 231, 192, 6, 159, 240,
+ 111, 115, 12, 231, 91, 11, 121, 49, 125, 157, 117, 122, 28, 228, 253,
+ 5, 47, 232, 210, 154, 11, 99, 58, 11, 92, 215, 31, 69, 254, 168,
+ 206, 130, 195, 253, 254, 79, 211, 209, 117, 157, 15, 215, 94, 225, 244,
+ 251, 253, 49, 222, 247, 134, 161, 173, 133, 86, 129, 253, 132, 88, 125,
+ 1, 175, 95, 244, 69, 148, 211, 100, 110, 42, 176, 101, 83, 184, 63,
+ 222, 247, 248, 223, 37, 151, 255, 26, 162, 109, 255, 136, 120, 255, 107,
+ 213, 94, 157, 246, 146, 225, 79, 45, 201, 168, 220, 254, 175, 90, 37,
+ 251, 63, 232, 68, 188, 70, 36, 241, 253, 159, 187, 203, 191, 254, 190,
+ 148, 114, 243, 59, 208, 254, 137, 211, 97, 107, 228, 234, 112, 90, 227,
+ 168, 202, 250, 175, 151, 145, 39, 252, 121, 107, 114, 113, 73, 72, 96,
+ 73, 98, 231, 138, 239, 255, 156, 59, 55, 75, 248, 37, 190, 164, 228,
+ 160, 105, 63, 215, 247, 65, 237, 143, 134, 167, 190, 149, 43, 52, 205,
+ 16, 239, 7, 204, 235, 189, 167, 228, 157, 117, 183, 194, 116, 151, 42,
+ 95, 255, 70, 200, 106, 214, 115, 137, 97, 9, 123, 67, 185, 189, 204,
+ 93, 156, 88, 188, 1, 121, 63, 124, 254, 54, 127, 126, 239, 168, 23,
+ 94, 52, 107, 243, 155, 125, 118, 41, 222, 255, 33, 255, 159, 191, 100,
+ 7, 127, 166, 242, 122, 143, 60, 225, 93, 221, 177, 226, 129, 199, 215,
+ 243, 190, 253, 125, 250, 231, 176, 188, 156, 60, 161, 201, 124, 241, 183,
+ 241, 255, 222, 182, 38, 252, 130, 209, 86, 178, 251, 43, 177, 253, 161,
+ 197, 193, 66, 225, 236, 64, 231, 217, 3, 111, 242, 245, 255, 196, 91,
+ 167, 29, 141, 99, 231, 106, 143, 204, 136, 227, 239, 79, 213, 143, 157,
+ 235, 152, 241, 179, 205, 249, 88, 70, 107, 46, 63, 202, 87, 101, 180,
+ 214, 246, 146, 222, 255, 49, 238, 61, 232, 60, 144, 61, 48, 226, 108,
+ 112, 38, 151, 223, 160, 185, 87, 28, 97, 103, 7, 57, 18, 13, 19,
+ 121, 253, 216, 152, 108, 109, 157, 148, 44, 103, 224, 137, 61, 188, 253,
+ 151, 199, 140, 119, 182, 251, 188, 163, 227, 246, 73, 13, 111, 191, 113,
+ 255, 19, 206, 159, 210, 46, 10, 255, 190, 183, 167, 156, 252, 73, 198,
+ 21, 246, 127, 208, 9, 150, 43, 146, 244, 238, 199, 93, 21, 224, 88,
+ 89, 126, 185, 247, 191, 108, 223, 36, 10, 93, 162, 191, 118, 212, 253,
+ 167, 80, 168, 138, 252, 77, 207, 231, 10, 95, 15, 254, 160, 164, 241,
+ 171, 207, 135, 189, 16, 240, 102, 133, 247, 127, 66, 79, 230, 9, 151,
+ 182, 169, 194, 226, 222, 111, 203, 231, 191, 250, 208, 217, 197, 11, 139,
+ 167, 11, 15, 93, 24, 206, 231, 239, 143, 178, 199, 195, 255, 73, 29,
+ 161, 237, 184, 116, 122, 229, 254, 255, 223, 60, 225, 74, 84, 231, 48,
+ 161, 243, 122, 142, 253, 229, 250, 206, 197, 175, 33, 207, 49, 102, 37,
+ 79, 47, 217, 178, 182, 232, 197, 179, 171, 138, 182, 223, 242, 200, 159,
+ 214, 191, 37, 225, 56, 127, 166, 242, 217, 249, 89, 66, 195, 167, 123,
+ 247, 121, 180, 68, 197, 229, 83, 125, 125, 100, 209, 243, 216, 83, 94,
+ 56, 176, 140, 219, 131, 245, 7, 85, 142, 201, 155, 86, 20, 239, 251,
+ 73, 244, 191, 177, 90, 31, 225, 82, 191, 230, 206, 247, 244, 165, 252,
+ 253, 143, 115, 205, 254, 41, 106, 114, 107, 150, 179, 241, 220, 219, 188,
+ 255, 224, 133, 190, 27, 138, 138, 235, 110, 21, 223, 231, 249, 122, 206,
+ 237, 146, 144, 173, 255, 150, 164, 74, 239, 255, 36, 134, 14, 208, 62,
+ 124, 250, 109, 231, 238, 14, 226, 254, 109, 246, 246, 3, 161, 31, 204,
+ 205, 21, 54, 31, 252, 146, 215, 223, 127, 49, 203, 121, 217, 180, 183,
+ 216, 231, 236, 44, 62, 254, 182, 167, 114, 29, 150, 85, 159, 134, 23,
+ 77, 23, 127, 159, 55, 229, 133, 88, 231, 186, 198, 83, 157, 103, 198,
+ 44, 45, 31, 255, 231, 86, 242, 252, 79, 83, 233, 251, 63, 149, 234,
+ 192, 171, 9, 227, 143, 40, 211, 239, 172, 223, 87, 244, 65, 114, 154,
+ 112, 102, 214, 198, 94, 85, 145, 127, 194, 31, 121, 130, 53, 182, 164,
+ 248, 55, 245, 178, 162, 31, 114, 103, 86, 120, 255, 103, 25, 100, 213,
+ 172, 244, 82, 209, 188, 31, 234, 241, 249, 206, 154, 171, 10, 171, 129,
+ 189, 214, 212, 246, 225, 124, 62, 114, 235, 212, 46, 190, 144, 30, 30,
+ 62, 227, 80, 229, 246, 191, 7, 240, 87, 197, 149, 132, 69, 132, 159,
+ 226, 242, 126, 122, 110, 73, 113, 247, 63, 243, 132, 58, 83, 123, 242,
+ 244, 249, 186, 239, 22, 61, 251, 85, 68, 81, 246, 29, 242, 111, 46,
+ 244, 224, 235, 127, 104, 251, 153, 66, 116, 226, 202, 35, 237, 63, 13,
+ 228, 242, 239, 255, 189, 189, 40, 226, 231, 60, 225, 219, 69, 63, 240,
+ 254, 60, 117, 42, 208, 241, 121, 202, 79, 197, 187, 234, 136, 242, 91,
+ 113, 228, 71, 109, 90, 78, 43, 103, 63, 85, 27, 254, 254, 87, 76,
+ 235, 73, 197, 39, 174, 207, 114, 174, 138, 17, 229, 255, 230, 245, 89,
+ 66, 108, 175, 179, 197, 239, 93, 189, 198, 229, 191, 4, 249, 199, 174,
+ 94, 43, 121, 95, 122, 255, 103, 88, 227, 16, 237, 150, 147, 163, 92,
+ 243, 3, 69, 249, 39, 7, 173, 15, 173, 6, 123, 215, 162, 240, 45,
+ 94, 191, 176, 196, 238, 124, 182, 246, 137, 226, 234, 187, 214, 112, 249,
+ 251, 180, 95, 235, 216, 180, 247, 141, 240, 199, 159, 177, 241, 250, 19,
+ 22, 181, 112, 109, 154, 106, 115, 190, 58, 248, 77, 46, 127, 250, 29,
+ 40, 250, 62, 200, 18, 127, 89, 61, 207, 253, 61, 95, 102, 249, 239,
+ 13, 35, 251, 218, 140, 118, 166, 75, 53, 232, 153, 248, 205, 97, 96,
+ 96, 144, 244, 142, 185, 248, 45, 137, 63, 202, 103, 137, 84, 122, 242,
+ 166, 231, 55, 85, 144, 255, 180, 251, 123, 18, 127, 233, 91, 194, 191,
+ 254, 46, 135, 125, 191, 247, 202, 221, 239, 168, 135, 73, 24, 110, 188,
+ 82, 63, 180, 133, 180, 101, 122, 90, 185, 207, 132, 239, 247, 158, 178,
+ 18, 143, 48, 228, 254, 129, 231, 125, 156, 253, 79, 185, 254, 221, 239,
+ 189, 215, 114, 253, 83, 224, 93, 80, 163, 127, 72, 23, 246, 191, 3,
+ 239, 62, 239, 81, 42, 241, 8, 195, 141, 151, 15, 158, 240, 163, 39,
+ 151, 159, 191, 251, 189, 151, 167, 196, 203, 87, 224, 249, 129, 39, 252,
+ 248, 254, 166, 114, 243, 119, 191, 247, 188, 148, 120, 126, 10, 188, 229,
+ 179, 16, 39, 18, 94, 209, 29, 227, 189, 207, 123, 67, 74, 60, 194,
+ 112, 227, 249, 131, 39, 252, 136, 130, 148, 114, 253, 187, 223, 123, 40,
+ 74, 60, 127, 5, 94, 225, 204, 203, 106, 194, 47, 75, 155, 90, 14,
+ 239, 126, 239, 53, 40, 241, 8, 195, 141, 23, 1, 158, 240, 203, 250,
+ 149, 199, 187, 223, 115, 114, 37, 94, 132, 2, 175, 116, 6, 116, 5,
+ 233, 64, 255, 244, 114, 120, 247, 123, 238, 86, 78, 159, 103, 40, 244,
+ 25, 60, 239, 227, 194, 242, 191, 41, 115, 191, 231, 56, 229, 244, 89,
+ 129, 119, 97, 58, 244, 25, 233, 248, 127, 141, 229, 231, 239, 62, 207,
+ 5, 202, 233, 243, 116, 133, 62, 131, 39, 252, 210, 27, 102, 223, 59,
+ 245, 249, 126, 152, 178, 62, 43, 240, 252, 192, 19, 126, 33, 75, 171,
+ 32, 143, 123, 61, 183, 46, 167, 207, 10, 188, 130, 28, 232, 51, 199,
+ 52, 85, 42, 143, 123, 97, 202, 127, 47, 51, 199, 131, 23, 8, 158,
+ 240, 149, 127, 127, 92, 150, 199, 125, 58, 40, 255, 86, 133, 2, 207,
+ 149, 125, 89, 77, 248, 241, 199, 43, 149, 199, 61, 17, 229, 223, 170,
+ 200, 246, 224, 69, 131, 231, 125, 188, 232, 145, 135, 230, 63, 236, 251,
+ 149, 120, 209, 10, 188, 50, 248, 2, 194, 47, 140, 79, 175, 196, 62,
+ 223, 123, 192, 242, 111, 143, 102, 121, 240, 44, 224, 9, 63, 126, 216,
+ 165, 74, 236, 243, 127, 195, 179, 40, 240, 200, 87, 241, 62, 222, 170,
+ 212, 62, 255, 167, 249, 99, 74, 60, 9, 63, 223, 113, 87, 251, 124,
+ 87, 76, 183, 15, 38, 191, 235, 246, 193, 101, 67, 160, 43, 241, 30,
+ 63, 204, 125, 176, 221, 104, 74, 70, 171, 70, 123, 98, 74, 176, 228,
+ 132, 221, 62, 216, 31, 117, 163, 135, 98, 61, 69, 167, 251, 150, 30,
+ 78, 241, 149, 109, 96, 166, 194, 6, 102, 72, 120, 141, 254, 241, 218,
+ 7, 19, 134, 108, 3, 193, 19, 254, 242, 122, 222, 251, 224, 8, 5,
+ 94, 169, 29, 250, 130, 116, 105, 200, 37, 175, 125, 48, 97, 200, 54,
+ 16, 60, 225, 151, 5, 121, 239, 131, 227, 21, 120, 23, 108, 232, 27,
+ 210, 254, 79, 121, 239, 131, 9, 67, 182, 129, 224, 9, 63, 250, 5,
+ 179, 215, 62, 56, 95, 129, 231, 7, 158, 240, 253, 119, 120, 239, 131,
+ 253, 20, 120, 5, 86, 232, 51, 245, 113, 171, 209, 107, 31, 76, 24,
+ 178, 13, 4, 207, 251, 24, 237, 189, 15, 14, 84, 224, 185, 166, 193,
+ 6, 34, 93, 214, 214, 123, 31, 76, 24, 178, 13, 4, 79, 248, 165,
+ 129, 38, 175, 125, 112, 180, 2, 175, 112, 36, 236, 11, 210, 236, 51,
+ 239, 125, 48, 97, 200, 235, 13, 60, 225, 151, 125, 225, 189, 15, 142,
+ 80, 224, 149, 142, 192, 122, 67, 186, 160, 200, 123, 31, 76, 24, 242,
+ 122, 3, 79, 248, 254, 193, 222, 251, 224, 120, 5, 222, 133, 225, 144,
+ 5, 210, 101, 19, 189, 247, 193, 132, 33, 175, 55, 240, 132, 31, 239,
+ 242, 222, 7, 231, 43, 240, 252, 192, 19, 126, 65, 247, 169, 94, 251,
+ 96, 63, 5, 94, 193, 48, 172, 55, 26, 243, 33, 239, 125, 48, 97,
+ 200, 235, 13, 60, 225, 199, 239, 243, 222, 7, 7, 42, 240, 92, 240,
+ 47, 132, 31, 223, 210, 123, 31, 76, 24, 242, 122, 3, 79, 248, 101,
+ 223, 121, 239, 131, 163, 135, 150, 247, 193, 132, 207, 54, 121, 239, 131,
+ 201, 239, 186, 125, 112, 96, 24, 124, 91, 102, 57, 31, 108, 215, 153,
+ 244, 228, 132, 105, 51, 236, 222, 6, 203, 62, 216, 130, 186, 5, 168,
+ 19, 93, 116, 75, 109, 241, 59, 83, 83, 142, 59, 134, 40, 250, 56,
+ 68, 194, 155, 225, 189, 15, 102, 10, 188, 229, 131, 17, 39, 12, 161,
+ 223, 45, 240, 222, 7, 19, 134, 188, 239, 2, 79, 248, 209, 179, 188,
+ 247, 193, 254, 10, 188, 194, 65, 152, 67, 164, 93, 58, 239, 125, 48,
+ 97, 200, 54, 16, 60, 225, 199, 127, 229, 189, 15, 142, 80, 224, 149,
+ 14, 132, 13, 68, 186, 32, 223, 123, 31, 76, 24, 178, 13, 4, 79,
+ 248, 165, 107, 188, 247, 193, 241, 10, 188, 11, 3, 128, 133, 116, 193,
+ 94, 239, 125, 48, 97, 200, 54, 16, 60, 225, 251, 77, 240, 222, 7,
+ 231, 43, 240, 252, 192, 19, 126, 190, 202, 123, 31, 236, 167, 192, 43,
+ 232, 15, 44, 164, 151, 247, 244, 222, 7, 19, 134, 108, 3, 193, 19,
+ 190, 235, 27, 239, 125, 112, 160, 2, 207, 213, 15, 178, 32, 204, 239,
+ 189, 247, 193, 132, 33, 219, 64, 240, 132, 95, 240, 246, 93, 109, 254,
+ 125, 245, 57, 90, 129, 87, 40, 96, 172, 72, 199, 135, 123, 239, 131,
+ 9, 67, 94, 111, 224, 9, 223, 47, 193, 123, 31, 28, 161, 192, 43,
+ 213, 98, 189, 33, 173, 252, 187, 245, 255, 171, 15, 38, 12, 121, 189,
+ 129, 39, 252, 248, 48, 239, 125, 112, 188, 2, 239, 66, 56, 214, 155,
+ 150, 246, 213, 119, 141, 137, 238, 235, 131, 9, 67, 94, 111, 224, 9,
+ 191, 192, 233, 189, 15, 206, 87, 224, 249, 129, 39, 124, 255, 14, 222,
+ 251, 96, 63, 5, 30, 249, 43, 194, 47, 248, 213, 123, 31, 76, 24,
+ 74, 31, 76, 248, 254, 159, 121, 239, 131, 201, 239, 186, 125, 112, 97,
+ 16, 226, 131, 33, 74, 31, 108, 231, 251, 95, 120, 94, 163, 93, 246,
+ 192, 30, 31, 236, 10, 165, 248, 19, 250, 90, 221, 228, 91, 86, 236,
+ 217, 7, 83, 190, 188, 230, 66, 165, 239, 91, 170, 121, 239, 131, 163,
+ 21, 120, 101, 125, 176, 230, 144, 182, 216, 188, 247, 193, 132, 33, 223,
+ 235, 0, 79, 248, 254, 83, 189, 247, 193, 22, 5, 30, 3, 79, 248,
+ 126, 81, 222, 251, 96, 166, 192, 91, 222, 27, 99, 69, 58, 255, 144,
+ 247, 62, 152, 48, 228, 152, 3, 60, 225, 199, 47, 241, 222, 7, 251,
+ 43, 240, 10, 123, 193, 127, 32, 29, 127, 208, 123, 31, 76, 24, 178,
+ 13, 4, 79, 248, 174, 120, 239, 125, 112, 132, 2, 175, 180, 39, 108,
+ 96, 47, 250, 13, 169, 169, 229, 108, 254, 255, 226, 131, 9, 67, 182,
+ 129, 224, 9, 63, 63, 194, 123, 31, 28, 175, 192, 187, 208, 3, 54,
+ 16, 233, 248, 54, 222, 251, 96, 194, 144, 109, 32, 120, 194, 143, 190,
+ 233, 189, 15, 206, 87, 224, 249, 129, 39, 252, 11, 23, 189, 247, 193,
+ 126, 10, 188, 130, 238, 152, 59, 164, 203, 126, 240, 126, 31, 76, 24,
+ 114, 204, 1, 158, 240, 227, 135, 120, 239, 131, 3, 21, 120, 174, 110,
+ 180, 199, 68, 31, 167, 121, 239, 131, 9, 67, 182, 127, 224, 9, 191,
+ 236, 160, 247, 62, 56, 90, 129, 87, 22, 130, 181, 129, 244, 133, 67,
+ 222, 223, 139, 38, 12, 217, 254, 129, 231, 125, 252, 214, 123, 31, 108,
+ 81, 224, 49, 240, 132, 111, 41, 243, 222, 7, 51, 5, 222, 114, 248,
+ 23, 194, 143, 239, 239, 189, 15, 38, 12, 217, 254, 129, 39, 124, 215,
+ 21, 239, 125, 176, 127, 112, 121, 31, 76, 248, 17, 7, 188, 247, 193,
+ 228, 119, 221, 62, 216, 127, 23, 100, 17, 86, 209, 7, 243, 15, 110,
+ 197, 187, 210, 240, 196, 30, 31, 28, 129, 186, 203, 81, 39, 250, 113,
+ 147, 111, 126, 174, 199, 7, 83, 190, 108, 3, 3, 69, 188, 194, 71,
+ 188, 247, 193, 132, 33, 219, 64, 240, 132, 239, 223, 209, 123, 31, 28,
+ 175, 192, 179, 92, 160, 251, 128, 24, 119, 92, 21, 124, 240, 5, 197,
+ 120, 243, 161, 47, 129, 244, 27, 185, 222, 251, 96, 194, 144, 251, 183,
+ 15, 58, 8, 124, 215, 58, 239, 125, 48, 97, 200, 58, 3, 158, 240,
+ 203, 54, 123, 239, 131, 153, 2, 111, 121, 33, 250, 135, 116, 244, 214,
+ 42, 60, 15, 46, 84, 248, 244, 189, 208, 23, 224, 185, 182, 120, 239,
+ 131, 9, 67, 246, 233, 224, 9, 63, 162, 177, 247, 62, 56, 66, 129,
+ 87, 250, 10, 124, 58, 210, 5, 45, 189, 247, 193, 132, 33, 235, 51,
+ 120, 194, 143, 111, 234, 189, 15, 142, 87, 224, 93, 216, 3, 249, 34,
+ 237, 58, 237, 189, 15, 38, 12, 217, 167, 131, 39, 252, 130, 51, 222,
+ 251, 224, 124, 5, 158, 31, 120, 194, 95, 126, 192, 123, 31, 236, 167,
+ 192, 43, 216, 13, 127, 73, 99, 158, 236, 189, 15, 38, 12, 217, 167,
+ 131, 39, 252, 130, 113, 222, 251, 224, 64, 5, 158, 235, 101, 96, 33,
+ 173, 252, 155, 161, 255, 171, 15, 38, 12, 217, 167, 131, 39, 252, 232,
+ 92, 239, 247, 193, 209, 10, 188, 178, 151, 160, 43, 132, 25, 97, 242,
+ 218, 7, 19, 134, 108, 175, 192, 19, 126, 193, 50, 239, 125, 176, 69,
+ 129, 199, 192, 19, 126, 97, 45, 239, 125, 48, 83, 224, 145, 191, 34,
+ 124, 255, 143, 188, 247, 193, 132, 161, 244, 193, 132, 159, 191, 202, 123,
+ 31, 76, 126, 215, 237, 131, 227, 183, 96, 172, 65, 21, 125, 112, 136,
+ 199, 1, 151, 123, 39, 171, 112, 39, 116, 127, 11, 189, 131, 100, 242,
+ 141, 31, 224, 241, 193, 148, 47, 219, 192, 157, 34, 222, 5, 149, 247,
+ 62, 56, 66, 129, 87, 186, 3, 125, 68, 218, 101, 170, 194, 59, 89,
+ 59, 20, 54, 16, 60, 225, 151, 25, 188, 247, 193, 241, 10, 188, 11,
+ 219, 49, 31, 72, 231, 167, 84, 225, 157, 172, 237, 10, 27, 8, 158,
+ 240, 93, 39, 170, 240, 78, 150, 2, 207, 15, 60, 225, 251, 47, 244,
+ 222, 7, 251, 41, 240, 10, 182, 97, 172, 72, 71, 111, 241, 222, 7,
+ 19, 134, 108, 3, 193, 19, 190, 197, 207, 123, 31, 28, 168, 192, 115,
+ 189, 8, 123, 128, 116, 129, 206, 123, 31, 76, 24, 178, 13, 4, 79,
+ 248, 236, 33, 239, 125, 112, 180, 2, 175, 108, 43, 100, 75, 125, 20,
+ 188, 247, 193, 132, 33, 219, 64, 240, 132, 239, 119, 205, 123, 31, 108,
+ 81, 224, 49, 240, 132, 191, 252, 119, 239, 125, 48, 83, 224, 45, 127,
+ 1, 178, 69, 250, 194, 23, 222, 251, 96, 194, 144, 247, 53, 224, 9,
+ 223, 127, 128, 247, 62, 216, 95, 129, 87, 248, 60, 198, 138, 244, 242,
+ 169, 222, 251, 96, 194, 144, 237, 31, 120, 194, 47, 248, 192, 123, 31,
+ 28, 161, 192, 43, 45, 128, 253, 67, 186, 240, 128, 247, 251, 96, 194,
+ 144, 237, 31, 120, 194, 47, 60, 227, 253, 62, 56, 94, 129, 87, 248,
+ 28, 236, 31, 210, 249, 59, 189, 247, 193, 132, 33, 207, 31, 120, 194,
+ 247, 143, 244, 222, 7, 71, 40, 240, 200, 95, 17, 126, 254, 223, 222,
+ 251, 96, 194, 80, 250, 96, 194, 207, 63, 234, 189, 15, 38, 191, 43,
+ 191, 147, 181, 10, 99, 221, 85, 209, 7, 119, 187, 139, 15, 190, 176,
+ 25, 235, 125, 181, 68, 35, 61, 127, 123, 130, 242, 101, 31, 178, 89,
+ 250, 219, 37, 35, 189, 247, 193, 249, 10, 60, 63, 240, 132, 95, 214,
+ 198, 123, 31, 236, 167, 192, 43, 216, 132, 249, 35, 204, 137, 222, 251,
+ 96, 194, 144, 125, 8, 120, 194, 47, 235, 228, 189, 15, 14, 84, 224,
+ 185, 54, 98, 253, 34, 29, 253, 138, 247, 62, 152, 48, 100, 31, 2,
+ 158, 240, 11, 158, 245, 222, 7, 71, 43, 240, 202, 54, 192, 135, 32,
+ 237, 90, 234, 189, 15, 38, 12, 217, 135, 128, 39, 252, 252, 245, 222,
+ 251, 96, 139, 2, 143, 129, 39, 124, 86, 223, 251, 231, 193, 76, 129,
+ 183, 252, 89, 248, 16, 26, 115, 105, 121, 159, 254, 191, 248, 96, 194,
+ 144, 125, 8, 120, 194, 247, 111, 236, 189, 15, 246, 87, 224, 21, 174,
+ 135, 255, 64, 58, 240, 124, 21, 222, 201, 90, 175, 176, 129, 224, 9,
+ 63, 254, 163, 42, 188, 147, 165, 192, 43, 93, 7, 27, 136, 180, 95,
+ 191, 138, 250, 252, 159, 223, 201, 90, 167, 240, 33, 224, 9, 127, 249,
+ 132, 42, 188, 147, 165, 192, 187, 176, 22, 62, 4, 233, 248, 209, 85,
+ 120, 39, 107, 173, 194, 254, 129, 39, 252, 130, 29, 85, 120, 39, 75,
+ 129, 231, 7, 158, 240, 253, 166, 87, 225, 157, 44, 5, 94, 193, 26,
+ 172, 53, 164, 11, 83, 238, 42, 143, 251, 191, 147, 181, 70, 97, 255,
+ 192, 19, 126, 252, 51, 85, 120, 39, 75, 129, 231, 130, 111, 33, 124,
+ 139, 111, 21, 222, 201, 90, 173, 176, 127, 224, 9, 191, 224, 100, 21,
+ 222, 201, 90, 125, 199, 59, 89, 72, 251, 189, 84, 133, 119, 178, 86,
+ 41, 158, 7, 255, 138, 185, 219, 82, 209, 7, 119, 191, 139, 15, 182,
+ 144, 207, 254, 141, 158, 167, 154, 124, 3, 179, 60, 251, 96, 202, 151,
+ 251, 184, 74, 250, 187, 146, 185, 85, 120, 39, 75, 129, 183, 124, 37,
+ 228, 129, 116, 254, 212, 42, 188, 147, 181, 82, 97, 3, 193, 19, 126,
+ 129, 174, 10, 239, 100, 41, 240, 10, 87, 192, 30, 32, 29, 161, 247,
+ 140, 87, 243, 63, 250, 96, 194, 144, 109, 32, 120, 194, 47, 59, 85,
+ 133, 119, 178, 20, 120, 165, 203, 177, 222, 144, 46, 155, 91, 133, 119,
+ 178, 150, 43, 198, 123, 30, 99, 5, 158, 223, 134, 42, 60, 15, 62,
+ 175, 24, 47, 120, 194, 143, 46, 244, 254, 219, 164, 8, 5, 94, 233,
+ 159, 24, 239, 121, 250, 182, 203, 123, 31, 76, 24, 178, 205, 7, 79,
+ 248, 174, 106, 85, 120, 30, 172, 192, 187, 240, 7, 198, 139, 116, 105,
+ 104, 21, 158, 7, 255, 161, 176, 249, 224, 9, 191, 244, 159, 42, 60,
+ 15, 86, 224, 249, 129, 39, 252, 232, 159, 171, 240, 60, 88, 129, 87,
+ 112, 14, 107, 23, 105, 203, 71, 85, 120, 30, 124, 78, 97, 243, 193,
+ 19, 126, 89, 100, 21, 158, 7, 43, 240, 92, 103, 97, 11, 144, 142,
+ 78, 170, 194, 243, 224, 179, 10, 155, 15, 158, 240, 227, 223, 173, 194,
+ 243, 96, 5, 94, 217, 239, 208, 61, 164, 93, 129, 222, 251, 96, 194,
+ 144, 99, 94, 240, 132, 95, 118, 170, 10, 207, 131, 21, 120, 12, 60,
+ 225, 71, 188, 88, 133, 231, 193, 10, 188, 229, 240, 47, 132, 31, 223,
+ 185, 10, 207, 131, 127, 83, 216, 123, 240, 188, 143, 231, 170, 240, 60,
+ 248, 183, 59, 158, 7, 255, 70, 239, 24, 86, 225, 121, 240, 175, 30,
+ 31, 124, 97, 9, 250, 182, 170, 162, 15, 238, 113, 23, 31, 28, 65,
+ 62, 123, 41, 202, 211, 111, 9, 86, 247, 236, 131, 41, 95, 182, 129,
+ 191, 72, 62, 120, 88, 21, 158, 7, 255, 162, 176, 129, 224, 9, 191,
+ 192, 191, 10, 207, 131, 21, 120, 23, 126, 134, 189, 66, 186, 112, 156,
+ 247, 62, 152, 48, 100, 27, 8, 158, 240, 11, 218, 123, 191, 15, 206,
+ 87, 224, 249, 129, 231, 125, 220, 230, 189, 15, 246, 83, 224, 21, 252,
+ 4, 27, 72, 125, 92, 227, 189, 15, 38, 12, 217, 6, 130, 39, 252,
+ 252, 69, 222, 251, 224, 64, 5, 158, 235, 71, 204, 29, 210, 17, 171,
+ 189, 223, 7, 19, 134, 108, 3, 193, 19, 126, 252, 112, 239, 125, 112,
+ 180, 2, 175, 236, 7, 216, 63, 164, 45, 254, 169, 94, 239, 131, 9,
+ 67, 182, 129, 224, 9, 191, 236, 17, 239, 125, 176, 69, 129, 199, 126,
+ 160, 247, 157, 160, 51, 191, 123, 239, 131, 153, 2, 111, 249, 247, 24,
+ 43, 97, 158, 242, 222, 7, 19, 134, 108, 3, 193, 19, 190, 69, 239,
+ 253, 62, 216, 95, 129, 87, 248, 29, 98, 94, 164, 163, 199, 86, 225,
+ 189, 232, 239, 20, 49, 32, 120, 194, 47, 27, 94, 133, 247, 162, 21,
+ 120, 165, 101, 176, 45, 223, 209, 183, 118, 85, 120, 47, 186, 76, 97,
+ 255, 192, 19, 126, 105, 70, 21, 222, 139, 86, 224, 21, 46, 3, 22,
+ 210, 165, 51, 189, 223, 7, 19, 134, 60, 127, 224, 9, 223, 127, 190,
+ 247, 62, 56, 66, 129, 87, 10, 255, 66, 248, 129, 26, 239, 125, 48,
+ 97, 200, 243, 7, 158, 247, 241, 77, 239, 125, 112, 252, 210, 242, 62,
+ 152, 240, 3, 111, 123, 239, 131, 201, 239, 186, 125, 176, 101, 14, 198,
+ 251, 107, 69, 31, 220, 243, 46, 62, 56, 159, 124, 246, 28, 241, 61,
+ 209, 192, 111, 60, 62, 152, 242, 101, 31, 178, 68, 194, 27, 236, 189,
+ 15, 246, 83, 224, 21, 44, 134, 189, 95, 66, 127, 159, 59, 221, 107,
+ 31, 76, 24, 178, 15, 1, 79, 248, 150, 209, 222, 251, 224, 64, 5,
+ 158, 235, 25, 248, 144, 197, 244, 251, 198, 222, 251, 96, 194, 144, 125,
+ 8, 120, 194, 191, 112, 221, 123, 31, 28, 173, 192, 43, 91, 4, 31,
+ 130, 180, 255, 10, 239, 125, 48, 97, 200, 62, 4, 60, 225, 71, 204,
+ 243, 222, 7, 91, 20, 120, 12, 60, 225, 23, 220, 246, 222, 7, 51,
+ 5, 222, 242, 133, 144, 237, 34, 250, 190, 203, 251, 231, 193, 132, 33,
+ 251, 16, 240, 132, 191, 156, 165, 122, 189, 15, 246, 87, 224, 21, 46,
+ 0, 22, 210, 129, 121, 222, 251, 96, 194, 144, 109, 224, 2, 122, 214,
+ 143, 117, 252, 179, 247, 62, 56, 66, 129, 87, 58, 31, 88, 11, 40,
+ 206, 247, 222, 7, 19, 134, 108, 3, 193, 19, 254, 242, 108, 239, 125,
+ 112, 188, 2, 239, 194, 60, 248, 15, 234, 99, 174, 247, 62, 152, 48,
+ 228, 24, 26, 60, 225, 23, 12, 246, 222, 7, 231, 43, 240, 252, 192,
+ 19, 126, 217, 38, 239, 125, 176, 159, 2, 175, 224, 105, 216, 63, 164,
+ 151, 79, 243, 222, 7, 19, 134, 108, 255, 192, 19, 126, 180, 221, 123,
+ 31, 28, 168, 192, 115, 205, 197, 220, 33, 93, 54, 219, 123, 31, 76,
+ 24, 178, 253, 3, 79, 248, 241, 75, 188, 247, 193, 209, 10, 60, 242,
+ 87, 188, 143, 78, 239, 125, 48, 97, 40, 125, 48, 225, 23, 94, 246,
+ 222, 7, 147, 223, 157, 167, 192, 187, 176, 68, 233, 131, 179, 116, 105,
+ 169, 156, 85, 124, 153, 196, 109, 152, 88, 6, 117, 75, 175, 136, 84,
+ 152, 228, 241, 193, 76, 209, 199, 229, 179, 165, 119, 178, 108, 222, 251,
+ 96, 194, 144, 109, 32, 225, 1, 159, 37, 120, 191, 15, 246, 87, 224,
+ 21, 62, 5, 125, 70, 218, 47, 199, 123, 31, 76, 24, 50, 222, 109,
+ 216, 64, 224, 249, 247, 170, 194, 247, 193, 183, 21, 54, 21, 60, 225,
+ 151, 157, 174, 194, 189, 104, 5, 94, 233, 45, 224, 33, 29, 189, 187,
+ 10, 247, 162, 111, 41, 108, 42, 120, 194, 95, 190, 162, 10, 223, 7,
+ 43, 240, 46, 220, 132, 62, 33, 29, 255, 114, 21, 190, 15, 190, 169,
+ 176, 169, 224, 9, 191, 52, 166, 10, 223, 7, 43, 240, 252, 192, 19,
+ 126, 89, 231, 42, 124, 31, 172, 192, 43, 184, 1, 155, 138, 116, 116,
+ 72, 21, 190, 15, 190, 161, 176, 169, 224, 9, 63, 255, 139, 42, 124,
+ 31, 172, 192, 115, 253, 11, 123, 133, 116, 252, 215, 85, 248, 62, 248,
+ 95, 133, 77, 5, 79, 248, 254, 111, 84, 225, 251, 96, 5, 94, 217,
+ 117, 216, 212, 127, 233, 123, 54, 239, 125, 48, 97, 200, 49, 37, 120,
+ 194, 143, 159, 236, 189, 15, 182, 40, 240, 24, 120, 194, 47, 59, 234,
+ 189, 15, 102, 10, 188, 229, 215, 16, 83, 94, 39, 251, 226, 189, 15,
+ 38, 12, 217, 158, 130, 39, 124, 127, 135, 247, 247, 162, 253, 21, 120,
+ 133, 87, 97, 11, 174, 209, 239, 230, 85, 225, 157, 172, 171, 10, 251,
+ 7, 158, 240, 203, 90, 87, 225, 157, 44, 5, 30, 247, 85, 72, 199,
+ 255, 88, 133, 119, 178, 174, 220, 241, 78, 22, 240, 10, 190, 251, 223,
+ 125, 240, 192, 97, 35, 163, 106, 227, 252, 213, 245, 250, 108, 168, 91,
+ 190, 243, 76, 190, 42, 150, 207, 52, 72, 244, 27, 17, 25, 116, 35,
+ 138, 177, 65, 77, 69, 39, 76, 215, 199, 32, 115, 68, 228, 240, 254,
+ 191, 96, 209, 4, 152, 12, 217, 118, 22, 96, 177, 26, 50, 89, 64,
+ 146, 209, 106, 67, 2, 86, 210, 206, 178, 89, 14, 155, 206, 178, 88,
+ 118, 186, 209, 132, 3, 236, 112, 14, 113, 57, 196, 161, 82, 150, 81,
+ 143, 130, 198, 4, 102, 210, 165, 27, 38, 5, 119, 155, 204, 50, 108,
+ 44, 41, 77, 151, 204, 44, 58, 61, 163, 139, 70, 125, 66, 154, 57,
+ 49, 149, 80, 211, 12, 122, 12, 68, 44, 26, 212, 35, 112, 50, 179,
+ 155, 237, 44, 49, 195, 154, 105, 160, 35, 227, 229, 236, 57, 22, 3,
+ 179, 165, 152, 179, 82, 13, 57, 204, 98, 182, 81, 25, 67, 154, 33,
+ 157, 241, 11, 86, 116, 139, 99, 4, 88, 13, 73, 84, 130, 46, 217,
+ 236, 214, 73, 33, 193, 147, 69, 222, 56, 157, 131, 101, 234, 210, 152,
+ 212, 174, 209, 98, 70, 227, 86, 115, 58, 65, 81, 29, 91, 90, 134,
+ 213, 146, 194, 116, 137, 60, 21, 16, 96, 75, 180, 26, 45, 118, 27,
+ 10, 81, 191, 145, 45, 102, 80, 113, 137, 195, 8, 77, 6, 150, 102,
+ 48, 1, 19, 135, 0, 26, 1, 31, 165, 141, 153, 232, 146, 141, 137,
+ 199, 0, 180, 156, 198, 2, 108, 134, 180, 52, 234, 68, 34, 3, 151,
+ 200, 2, 50, 76, 122, 115, 92, 66, 70, 18, 227, 12, 13, 138, 51,
+ 28, 42, 209, 156, 110, 161, 137, 97, 188, 231, 54, 131, 33, 149, 233,
+ 173, 186, 172, 233, 102, 244, 55, 197, 156, 166, 103, 137, 105, 70, 139,
+ 13, 35, 166, 179, 193, 164, 103, 38, 131, 157, 146, 56, 81, 10, 24,
+ 54, 94, 129, 87, 71, 5, 51, 161, 74, 231, 32, 38, 246, 31, 157,
+ 195, 60, 192, 73, 165, 99, 54, 168, 31, 1, 233, 70, 75, 186, 206,
+ 50, 41, 8, 50, 48, 167, 50, 18, 116, 146, 149, 198, 68, 220, 180,
+ 12, 93, 154, 209, 158, 195, 236, 22, 93, 178, 129, 79, 9, 38, 34,
+ 193, 136, 198, 178, 173, 6, 11, 203, 161, 131, 61, 139, 250, 96, 207,
+ 162, 46, 208, 165, 68, 179, 222, 64, 50, 177, 240, 114, 1, 22, 93,
+ 98, 170, 65, 79, 2, 103, 118, 67, 118, 162, 153, 161, 49, 187, 116,
+ 52, 25, 146, 249, 44, 234, 185, 64, 3, 204, 9, 83, 13, 137, 152,
+ 97, 148, 99, 22, 171, 121, 170, 120, 204, 225, 199, 233, 84, 195, 66,
+ 191, 41, 99, 78, 178, 77, 10, 153, 204, 231, 136, 206, 40, 204, 59,
+ 150, 136, 113, 90, 211, 209, 118, 26, 179, 50, 192, 50, 76, 158, 33,
+ 41, 46, 19, 209, 7, 46, 37, 233, 18, 153, 201, 108, 165, 19, 114,
+ 232, 20, 144, 162, 51, 233, 209, 169, 0, 11, 151, 96, 128, 205, 78,
+ 103, 27, 179, 81, 95, 108, 84, 10, 50, 164, 163, 221, 74, 163, 177,
+ 101, 164, 161, 103, 137, 152, 26, 70, 74, 199, 149, 172, 67, 128, 222,
+ 108, 180, 119, 236, 208, 17, 92, 162, 46, 45, 45, 1, 67, 165, 84,
+ 166, 193, 106, 51, 154, 77, 76, 199, 160, 111, 124, 104, 188, 74, 80,
+ 143, 201, 152, 243, 116, 29, 169, 70, 130, 97, 18, 82, 72, 216, 39,
+ 117, 155, 140, 255, 197, 102, 209, 69, 196, 35, 57, 140, 174, 163, 73,
+ 36, 141, 54, 3, 151, 166, 61, 195, 154, 144, 1, 53, 22, 23, 125,
+ 162, 217, 100, 183, 210, 138, 228, 35, 73, 166, 67, 2, 29, 48, 203,
+ 118, 106, 123, 186, 65, 172, 170, 55, 88, 236, 41, 34, 203, 225, 209,
+ 158, 56, 87, 86, 179, 133, 47, 98, 98, 114, 220, 12, 95, 209, 98,
+ 14, 24, 18, 176, 65, 103, 231, 50, 166, 51, 108, 2, 73, 152, 235,
+ 134, 13, 66, 72, 2, 38, 179, 209, 124, 36, 25, 13, 113, 124, 88,
+ 152, 96, 76, 103, 90, 70, 178, 145, 43, 115, 2, 178, 12, 166, 76,
+ 170, 162, 207, 176, 210, 56, 49, 103, 36, 33, 190, 142, 179, 153, 193,
+ 100, 176, 38, 231, 48, 189, 17, 3, 177, 97, 162, 68, 173, 7, 195,
+ 85, 130, 165, 232, 140, 38, 59, 2, 52, 123, 16, 29, 130, 25, 148,
+ 85, 44, 161, 75, 183, 192, 42, 232, 244, 114, 29, 152, 108, 200, 205,
+ 12, 247, 14, 88, 172, 89, 126, 53, 69, 151, 102, 182, 217, 161, 159,
+ 1, 233, 200, 157, 212, 107, 50, 163, 153, 181, 89, 12, 137, 86, 126,
+ 76, 230, 199, 4, 150, 110, 180, 90, 233, 144, 76, 135, 4, 166, 75,
+ 79, 176, 210, 129, 115, 201, 116, 96, 134, 116, 250, 89, 95, 147, 88,
+ 1, 243, 206, 116, 105, 150, 20, 29, 131, 213, 225, 57, 108, 58, 77,
+ 6, 211, 233, 245, 44, 149, 132, 144, 2, 141, 195, 218, 213, 7, 241,
+ 99, 48, 31, 113, 48, 89, 8, 43, 202, 98, 169, 192, 20, 144, 133,
+ 72, 100, 86, 104, 51, 21, 231, 99, 224, 215, 197, 241, 101, 36, 120,
+ 114, 18, 204, 102, 18, 115, 114, 2, 172, 7, 214, 65, 156, 104, 18,
+ 33, 86, 190, 68, 226, 72, 227, 232, 156, 70, 115, 2, 43, 27, 68,
+ 170, 106, 194, 140, 27, 249, 47, 16, 179, 164, 20, 234, 102, 26, 173,
+ 170, 164, 20, 62, 209, 217, 57, 252, 34, 211, 231, 64, 221, 73, 22,
+ 162, 177, 238, 222, 125, 50, 231, 76, 25, 48, 87, 54, 40, 179, 129,
+ 219, 43, 115, 26, 228, 110, 201, 166, 67, 14, 29, 166, 51, 200, 146,
+ 40, 152, 217, 176, 32, 179, 57, 23, 0, 45, 230, 138, 141, 35, 230,
+ 141, 155, 94, 146, 42, 166, 158, 95, 130, 180, 9, 8, 22, 152, 214,
+ 171, 213, 108, 167, 83, 150, 81, 26, 46, 250, 171, 151, 116, 214, 158,
+ 130, 188, 20, 44, 31, 42, 72, 133, 116, 88, 183, 140, 86, 59, 105,
+ 78, 74, 16, 75, 193, 60, 6, 177, 36, 28, 67, 88, 138, 17, 157,
+ 167, 162, 180, 120, 184, 102, 233, 236, 113, 38, 43, 179, 152, 236, 182,
+ 12, 126, 204, 4, 182, 205, 156, 150, 33, 158, 50, 153, 217, 138, 134,
+ 50, 196, 83, 38, 55, 217, 25, 252, 8, 47, 151, 138, 133, 135, 90,
+ 226, 25, 233, 4, 244, 61, 193, 48, 221, 206, 76, 88, 119, 196, 102,
+ 194, 54, 113, 195, 4, 163, 37, 122, 41, 24, 54, 172, 173, 0, 114,
+ 27, 9, 228, 40, 205, 86, 216, 54, 202, 227, 174, 193, 144, 201, 27,
+ 197, 48, 245, 40, 133, 106, 65, 116, 192, 172, 193, 28, 26, 248, 188,
+ 19, 71, 230, 140, 116, 65, 92, 2, 41, 8, 46, 153, 168, 227, 217,
+ 230, 36, 150, 3, 10, 32, 235, 147, 164, 75, 55, 166, 229, 112, 135,
+ 26, 144, 153, 132, 165, 207, 103, 62, 145, 79, 44, 157, 116, 122, 43,
+ 183, 185, 48, 86, 92, 61, 144, 13, 11, 100, 39, 227, 67, 141, 90,
+ 117, 22, 172, 16, 123, 186, 206, 150, 202, 50, 131, 88, 102, 48, 203,
+ 12, 97, 153, 221, 152, 37, 195, 132, 235, 162, 185, 206, 200, 148, 150,
+ 39, 4, 69, 19, 106, 50, 115, 211, 138, 205, 12, 164, 104, 39, 219,
+ 29, 192, 93, 0, 150, 117, 90, 134, 157, 27, 86, 76, 117, 150, 129,
+ 91, 163, 0, 125, 22, 181, 41, 165, 48, 110, 76, 47, 169, 127, 34,
+ 7, 193, 145, 252, 113, 82, 18, 55, 237, 233, 88, 33, 64, 209, 139,
+ 39, 187, 120, 74, 231, 221, 13, 208, 139, 167, 116, 82, 150, 0, 120,
+ 114, 99, 98, 106, 14, 159, 115, 248, 69, 210, 139, 0, 51, 172, 182,
+ 45, 35, 221, 44, 89, 110, 180, 201, 235, 219, 210, 205, 102, 73, 117,
+ 176, 118, 244, 198, 76, 110, 63, 225, 46, 68, 253, 178, 39, 113, 109,
+ 200, 226, 81, 67, 6, 63, 102, 242, 99, 22, 154, 196, 26, 230, 209,
+ 11, 124, 143, 184, 18, 200, 174, 91, 164, 137, 196, 57, 136, 14, 193,
+ 116, 8, 161, 3, 173, 77, 41, 194, 128, 252, 161, 186, 228, 173, 172,
+ 180, 8, 3, 116, 226, 138, 11, 128, 75, 55, 144, 71, 206, 50, 91,
+ 185, 7, 74, 208, 33, 141, 160, 33, 9, 94, 64, 90, 2, 102, 88,
+ 113, 58, 235, 221, 62, 76, 47, 45, 10, 184, 91, 242, 7, 76, 239,
+ 102, 204, 9, 30, 15, 33, 182, 103, 52, 101, 74, 105, 76, 19, 196,
+ 106, 19, 165, 196, 205, 58, 4, 46, 250, 104, 234, 17, 231, 50, 44,
+ 238, 11, 89, 176, 201, 88, 215, 60, 137, 115, 166, 81, 172, 146, 96,
+ 206, 144, 188, 175, 62, 195, 130, 238, 211, 49, 41, 137, 78, 228, 212,
+ 113, 34, 75, 108, 75, 162, 31, 52, 135, 147, 132, 14, 97, 101, 195,
+ 214, 144, 226, 66, 111, 173, 118, 35, 204, 63, 220, 46, 228, 96, 135,
+ 241, 215, 103, 164, 167, 231, 196, 5, 49, 171, 187, 12, 13, 144, 108,
+ 162, 30, 58, 99, 207, 166, 120, 138, 132, 11, 127, 14, 11, 142, 104,
+ 197, 12, 31, 203, 125, 153, 57, 45, 13, 54, 128, 174, 99, 224, 148,
+ 155, 70, 161, 137, 197, 12, 125, 72, 72, 144, 103, 9, 142, 132, 151,
+ 33, 169, 37, 67, 88, 124, 4, 110, 38, 24, 38, 218, 104, 195, 138,
+ 48, 91, 140, 137, 3, 36, 3, 40, 42, 160, 9, 50, 35, 103, 2,
+ 147, 101, 20, 253, 108, 138, 25, 70, 31, 135, 100, 58, 36, 208, 33,
+ 149, 77, 55, 64, 165, 113, 72, 166, 67, 2, 29, 82, 201, 252, 167,
+ 98, 253, 217, 236, 146, 37, 52, 219, 50, 172, 6, 150, 108, 197, 252,
+ 33, 42, 34, 145, 19, 19, 101, 206, 30, 173, 211, 27, 17, 237, 218,
+ 82, 115, 56, 62, 218, 49, 242, 198, 104, 22, 233, 204, 87, 56, 49,
+ 41, 70, 238, 3, 172, 252, 152, 204, 143, 9, 252, 152, 202, 143, 162,
+ 7, 0, 3, 167, 44, 90, 5, 240, 50, 131, 94, 112, 103, 206, 244,
+ 8, 130, 72, 62, 230, 36, 146, 15, 78, 228, 195, 233, 4, 93, 78,
+ 129, 191, 162, 224, 1, 188, 17, 209, 0, 143, 8, 69, 183, 1, 229,
+ 77, 193, 82, 177, 200, 28, 133, 9, 8, 152, 16, 11, 162, 48, 50,
+ 37, 55, 2, 95, 142, 131, 17, 150, 28, 28, 14, 70, 186, 76, 37,
+ 105, 46, 177, 72, 147, 13, 38, 44, 59, 216, 126, 30, 125, 232, 210,
+ 81, 202, 150, 205, 108, 136, 91, 40, 28, 48, 208, 1, 222, 32, 25,
+ 125, 160, 104, 129, 135, 123, 60, 108, 16, 131, 230, 12, 30, 180, 24,
+ 244, 201, 134, 209, 252, 56, 144, 31, 163, 88, 18, 92, 15, 98, 84,
+ 3, 10, 101, 91, 200, 87, 231, 240, 99, 146, 213, 48, 141, 51, 52,
+ 30, 49, 166, 207, 182, 37, 166, 176, 28, 58, 100, 235, 96, 159, 114,
+ 232, 144, 77, 139, 214, 134, 58, 252, 100, 211, 37, 33, 226, 129, 118,
+ 147, 173, 135, 17, 54, 81, 160, 13, 20, 10, 204, 141, 233, 124, 54,
+ 160, 96, 92, 127, 220, 33, 174, 77, 178, 203, 220, 185, 115, 78, 111,
+ 22, 199, 102, 182, 65, 201, 173, 182, 56, 155, 65, 236, 54, 133, 37,
+ 192, 179, 167, 35, 32, 163, 179, 88, 138, 56, 138, 1, 232, 108, 20,
+ 179, 200, 59, 163, 25, 113, 127, 3, 173, 20, 153, 36, 106, 94, 100,
+ 211, 205, 153, 70, 137, 69, 0, 153, 110, 192, 196, 5, 192, 110, 32,
+ 210, 15, 160, 232, 74, 52, 29, 56, 82, 76, 19, 144, 108, 53, 103,
+ 88, 104, 43, 129, 101, 67, 122, 29, 144, 132, 42, 136, 176, 80, 24,
+ 162, 48, 154, 25, 223, 39, 136, 177, 19, 102, 138, 229, 80, 136, 111,
+ 37, 171, 203, 157, 14, 31, 52, 154, 203, 242, 88, 20, 74, 121, 236,
+ 137, 5, 43, 80, 97, 109, 200, 39, 203, 215, 168, 164, 219, 38, 209,
+ 21, 11, 207, 33, 151, 174, 75, 19, 57, 93, 14, 15, 188, 18, 17,
+ 212, 241, 173, 150, 206, 74, 150, 133, 161, 139, 188, 91, 201, 86, 35,
+ 109, 87, 200, 193, 129, 210, 179, 89, 58, 4, 154, 141, 109, 64, 142,
+ 153, 226, 23, 30, 140, 242, 179, 142, 199, 53, 57, 82, 58, 71, 74,
+ 147, 216, 101, 38, 135, 163, 137, 187, 44, 106, 60, 1, 30, 9, 151,
+ 160, 85, 217, 210, 25, 110, 35, 33, 25, 19, 14, 187, 203, 123, 168,
+ 103, 220, 181, 96, 153, 51, 238, 6, 129, 46, 70, 12, 217, 252, 100,
+ 52, 241, 62, 34, 201, 207, 80, 66, 216, 35, 150, 106, 64, 152, 133,
+ 77, 41, 157, 117, 60, 244, 227, 44, 47, 98, 53, 243, 86, 51, 131,
+ 245, 36, 0, 163, 157, 92, 45, 136, 130, 1, 84, 161, 20, 204, 31,
+ 84, 204, 142, 117, 202, 18, 225, 175, 48, 43, 140, 162, 43, 152, 24,
+ 62, 61, 36, 70, 218, 174, 225, 76, 243, 150, 14, 243, 148, 32, 30,
+ 205, 188, 211, 169, 22, 51, 0, 224, 251, 80, 129, 118, 56, 180, 101,
+ 165, 157, 176, 168, 4, 36, 213, 108, 126, 164, 189, 130, 53, 135, 199,
+ 152, 105, 226, 34, 231, 187, 60, 113, 187, 107, 225, 209, 25, 109, 189,
+ 210, 200, 130, 144, 191, 228, 219, 48, 163, 61, 77, 220, 159, 235, 141,
+ 86, 73, 39, 145, 63, 169, 23, 237, 0, 147, 40, 146, 182, 242, 16,
+ 195, 36, 45, 89, 88, 157, 180, 12, 132, 116, 180, 183, 151, 55, 238,
+ 86, 131, 157, 246, 213, 52, 38, 178, 131, 216, 1, 33, 39, 195, 106,
+ 74, 202, 48, 37, 210, 30, 40, 128, 174, 88, 152, 217, 108, 33, 33,
+ 217, 140, 124, 173, 5, 112, 179, 64, 198, 1, 195, 66, 199, 121, 100,
+ 193, 239, 203, 241, 208, 10, 61, 20, 21, 75, 148, 45, 133, 58, 113,
+ 80, 155, 180, 20, 49, 178, 176, 24, 179, 227, 160, 124, 113, 124, 3,
+ 110, 207, 182, 75, 114, 2, 71, 183, 152, 3, 44, 57, 113, 100, 234,
+ 56, 99, 200, 228, 174, 25, 28, 100, 96, 23, 253, 154, 232, 250, 116,
+ 153, 6, 238, 202, 236, 134, 116, 11, 13, 191, 7, 166, 129, 26, 114,
+ 243, 98, 56, 234, 78, 81, 175, 50, 220, 9, 218, 217, 32, 67, 153,
+ 180, 25, 166, 201, 201, 28, 123, 138, 217, 228, 78, 217, 72, 251, 221,
+ 9, 105, 63, 104, 147, 125, 149, 141, 235, 35, 95, 222, 100, 80, 56,
+ 3, 239, 174, 19, 23, 60, 95, 68, 220, 222, 219, 105, 147, 164, 207,
+ 22, 249, 28, 226, 115, 152, 184, 20, 196, 117, 192, 75, 98, 42, 69,
+ 179, 9, 134, 108, 40, 87, 35, 114, 247, 32, 93, 170, 157, 223, 153,
+ 201, 164, 72, 25, 209, 35, 246, 7, 136, 255, 2, 16, 0, 6, 32,
+ 2, 12, 224, 197, 3, 16, 119, 34, 224, 48, 100, 160, 233, 148, 105,
+ 48, 64, 70, 147, 148, 202, 154, 70, 24, 30, 155, 64, 5, 41, 224,
+ 68, 38, 157, 40, 41, 181, 195, 121, 131, 85, 50, 172, 118, 143, 193,
+ 193, 181, 108, 58, 228, 240, 18, 113, 182, 44, 4, 163, 156, 51, 144,
+ 221, 165, 43, 98, 30, 49, 98, 22, 93, 5, 4, 191, 117, 33, 178,
+ 124, 13, 113, 179, 7, 45, 163, 60, 90, 80, 201, 6, 113, 223, 141,
+ 138, 202, 36, 93, 38, 45, 232, 216, 33, 211, 108, 212, 75, 5, 202,
+ 103, 240, 225, 98, 178, 245, 50, 128, 156, 226, 253, 230, 234, 157, 97,
+ 228, 75, 72, 188, 141, 35, 121, 37, 218, 210, 192, 206, 113, 223, 64,
+ 235, 64, 186, 233, 67, 81, 99, 55, 178, 224, 54, 67, 16, 29, 130,
+ 233, 16, 194, 32, 13, 189, 217, 196, 111, 44, 96, 69, 114, 80, 210,
+ 7, 190, 200, 172, 217, 160, 28, 177, 42, 101, 144, 136, 160, 74, 162,
+ 156, 197, 35, 13, 26, 242, 230, 235, 145, 210, 112, 42, 144, 21, 114,
+ 68, 38, 93, 151, 152, 66, 203, 64, 220, 225, 243, 18, 124, 199, 101,
+ 32, 173, 195, 153, 124, 19, 133, 201, 220, 95, 138, 93, 224, 67, 225,
+ 183, 207, 96, 33, 147, 2, 249, 145, 119, 120, 154, 120, 228, 253, 158,
+ 22, 130, 192, 108, 154, 164, 135, 34, 99, 225, 55, 29, 209, 4, 44,
+ 10, 173, 38, 110, 101, 48, 26, 126, 203, 9, 97, 173, 184, 156, 16,
+ 86, 240, 190, 99, 203, 75, 55, 90, 40, 34, 68, 244, 74, 71, 132,
+ 167, 60, 80, 32, 51, 38, 37, 121, 52, 140, 184, 49, 81, 140, 235,
+ 40, 234, 48, 233, 16, 125, 144, 150, 138, 91, 122, 132, 120, 226, 54,
+ 144, 70, 194, 221, 14, 213, 225, 97, 111, 138, 49, 77, 79, 140, 168,
+ 151, 4, 139, 16, 131, 20, 132, 74, 82, 207, 176, 113, 16, 55, 254,
+ 48, 199, 54, 38, 25, 15, 19, 98, 46, 115, 22, 109, 216, 209, 65,
+ 88, 124, 222, 35, 244, 156, 239, 221, 41, 250, 183, 88, 13, 10, 239,
+ 71, 238, 221, 227, 39, 197, 158, 80, 21, 168, 165, 89, 12, 17, 204,
+ 180, 167, 33, 247, 193, 131, 44, 233, 182, 25, 122, 153, 158, 32, 174,
+ 107, 92, 12, 225, 251, 158, 100, 233, 204, 131, 209, 116, 76, 191, 45,
+ 205, 204, 55, 76, 220, 87, 100, 99, 71, 238, 137, 80, 41, 135, 162,
+ 91, 218, 96, 73, 230, 141, 16, 221, 60, 76, 1, 44, 64, 0, 217,
+ 68, 186, 141, 151, 68, 13, 33, 108, 227, 231, 116, 115, 134, 205, 16,
+ 135, 136, 194, 16, 103, 53, 112, 67, 72, 119, 123, 232, 10, 212, 206,
+ 150, 102, 148, 78, 113, 162, 109, 149, 18, 8, 219, 36, 206, 144, 35,
+ 115, 114, 94, 10, 65, 80, 85, 210, 118, 27, 2, 65, 152, 116, 140,
+ 54, 93, 202, 166, 218, 18, 135, 218, 110, 78, 206, 75, 193, 254, 134,
+ 240, 109, 8, 12, 245, 54, 66, 181, 81, 35, 6, 202, 51, 80, 158,
+ 129, 242, 12, 200, 75, 162, 114, 73, 84, 46, 137, 202, 37, 241, 114,
+ 54, 125, 10, 56, 58, 80, 141, 36, 170, 145, 68, 53, 146, 168, 6,
+ 228, 71, 141, 227, 200, 121, 3, 231, 169, 150, 137, 208, 77, 132, 110,
+ 202, 2, 161, 54, 229, 36, 81, 78, 18, 114, 146, 40, 199, 12, 95,
+ 23, 20, 220, 11, 138, 135, 64, 138, 51, 220, 253, 137, 89, 70, 41,
+ 75, 188, 241, 141, 164, 196, 137, 158, 211, 76, 62, 131, 132, 164, 75,
+ 163, 57, 98, 208, 69, 76, 8, 229, 75, 215, 113, 129, 79, 150, 24,
+ 0, 199, 97, 30, 40, 0, 21, 79, 113, 146, 42, 74, 41, 110, 108,
+ 168, 42, 221, 59, 227, 53, 137, 129, 30, 27, 249, 125, 56, 126, 206,
+ 145, 90, 71, 236, 153, 38, 222, 99, 19, 91, 140, 147, 235, 208, 21,
+ 44, 26, 40, 53, 178, 220, 146, 15, 72, 164, 37, 225, 185, 245, 200,
+ 232, 230, 113, 0, 15, 41, 2, 192, 114, 134, 246, 233, 226, 182, 132,
+ 116, 151, 124, 121, 0, 48, 41, 130, 225, 102, 152, 14, 193, 244, 248,
+ 34, 217, 96, 31, 225, 222, 24, 219, 205, 201, 201, 105, 6, 57, 137,
+ 74, 25, 34, 135, 30, 43, 19, 88, 17, 70, 93, 154, 92, 142, 22,
+ 56, 173, 53, 43, 221, 69, 75, 163, 157, 3, 236, 53, 67, 56, 15,
+ 61, 52, 80, 104, 79, 27, 66, 121, 247, 141, 234, 50, 79, 101, 196,
+ 200, 129, 34, 160, 145, 226, 253, 97, 104, 60, 157, 121, 129, 4, 179,
+ 62, 71, 220, 179, 103, 164, 65, 213, 105, 179, 64, 243, 66, 203, 3,
+ 203, 58, 64, 60, 27, 77, 60, 252, 163, 139, 193, 140, 246, 239, 162,
+ 132, 211, 115, 96, 118, 113, 209, 146, 97, 231, 143, 22, 108, 98, 105,
+ 68, 77, 33, 244, 36, 64, 76, 209, 196, 128, 232, 214, 142, 190, 59,
+ 183, 24, 124, 171, 47, 198, 217, 60, 72, 53, 98, 59, 79, 251, 7,
+ 216, 88, 61, 197, 75, 201, 220, 32, 83, 130, 143, 208, 125, 63, 36,
+ 88, 230, 96, 98, 77, 122, 184, 135, 0, 30, 36, 96, 188, 169, 134,
+ 68, 179, 5, 145, 28, 191, 243, 170, 167, 251, 14, 250, 73, 65, 212,
+ 65, 3, 173, 243, 113, 20, 80, 163, 5, 50, 31, 60, 156, 229, 19,
+ 194, 173, 167, 116, 63, 129, 243, 210, 45, 4, 90, 222, 58, 180, 226,
+ 169, 131, 201, 206, 72, 187, 35, 75, 175, 55, 232, 43, 43, 105, 182,
+ 167, 24, 172, 212, 60, 172, 30, 249, 113, 168, 14, 78, 100, 233, 41,
+ 32, 231, 113, 28, 140, 32, 120, 169, 101, 200, 221, 205, 33, 38, 16,
+ 123, 64, 55, 167, 68, 142, 180, 203, 106, 4, 0, 221, 24, 129, 117,
+ 139, 131, 54, 197, 5, 201, 28, 221, 20, 53, 235, 220, 185, 30, 30,
+ 106, 103, 142, 134, 70, 200, 250, 19, 96, 55, 75, 162, 39, 113, 199,
+ 144, 86, 39, 195, 10, 39, 98, 2, 210, 176, 103, 226, 240, 180, 129,
+ 21, 109, 59, 111, 94, 230, 225, 45, 165, 4, 114, 185, 167, 161, 28,
+ 206, 240, 108, 49, 11, 222, 139, 130, 94, 8, 150, 159, 3, 232, 168,
+ 75, 179, 241, 93, 25, 109, 29, 233, 44, 62, 21, 9, 224, 55, 78,
+ 249, 237, 40, 242, 60, 196, 208, 253, 77, 29, 127, 162, 68, 30, 0,
+ 110, 147, 223, 11, 193, 58, 147, 166, 134, 183, 195, 239, 251, 240, 172,
+ 32, 73, 144, 65, 242, 53, 145, 35, 31, 238, 174, 65, 188, 52, 137,
+ 238, 193, 72, 0, 138, 71, 6, 226, 141, 92, 43, 53, 75, 12, 38,
+ 128, 223, 54, 166, 4, 73, 73, 7, 149, 32, 85, 162, 187, 136, 210,
+ 189, 150, 0, 186, 217, 194, 55, 147, 20, 211, 27, 249, 67, 138, 0,
+ 76, 60, 221, 183, 7, 182, 123, 52, 124, 103, 66, 207, 190, 232, 44,
+ 46, 92, 189, 24, 61, 195, 185, 26, 164, 123, 79, 110, 221, 163, 218,
+ 18, 47, 173, 58, 186, 65, 79, 119, 12, 161, 229, 113, 162, 138, 103,
+ 154, 177, 129, 32, 189, 54, 153, 248, 95, 5, 176, 67, 165, 50, 68,
+ 185, 89, 232, 109, 92, 210, 158, 184, 100, 56, 64, 146, 152, 200, 144,
+ 238, 232, 232, 54, 131, 180, 123, 226, 235, 114, 82, 207, 201, 76, 188,
+ 106, 182, 160, 9, 171, 251, 182, 147, 152, 114, 171, 50, 51, 97, 183,
+ 66, 237, 218, 248, 34, 69, 239, 229, 12, 10, 192, 177, 66, 41, 114,
+ 10, 72, 38, 91, 199, 183, 108, 201, 210, 131, 39, 158, 195, 111, 228,
+ 209, 83, 72, 138, 51, 184, 43, 231, 174, 151, 162, 70, 126, 79, 84,
+ 103, 76, 163, 51, 162, 29, 143, 36, 224, 174, 61, 9, 186, 249, 98,
+ 47, 23, 74, 40, 2, 139, 4, 132, 132, 28, 52, 145, 30, 111, 136,
+ 240, 6, 91, 16, 29, 184, 129, 8, 225, 227, 21, 227, 47, 29, 177,
+ 208, 69, 126, 66, 175, 96, 50, 12, 38, 190, 214, 165, 199, 47, 210,
+ 189, 68, 108, 117, 68, 69, 73, 227, 61, 11, 128, 242, 64, 138, 180,
+ 50, 104, 254, 40, 60, 225, 83, 109, 35, 195, 41, 26, 116, 190, 170,
+ 166, 211, 146, 158, 158, 46, 190, 77, 19, 51, 33, 186, 255, 139, 244,
+ 188, 159, 158, 94, 100, 240, 35, 182, 155, 88, 10, 25, 226, 137, 98,
+ 147, 52, 51, 100, 151, 193, 143, 124, 177, 98, 222, 51, 48, 195, 140,
+ 2, 107, 54, 140, 2, 146, 97, 16, 90, 20, 245, 29, 17, 83, 176,
+ 141, 31, 141, 252, 152, 196, 143, 180, 13, 79, 12, 225, 57, 33, 60,
+ 39, 132, 231, 116, 227, 57, 221, 120, 78, 55, 172, 83, 204, 63, 29,
+ 146, 216, 224, 126, 64, 76, 176, 234, 16, 42, 15, 198, 150, 122, 168,
+ 33, 39, 138, 239, 107, 193, 176, 49, 124, 159, 203, 91, 141, 193, 38,
+ 109, 24, 137, 148, 24, 22, 205, 159, 55, 14, 32, 119, 220, 87, 188,
+ 165, 50, 152, 111, 58, 249, 35, 207, 193, 233, 81, 25, 73, 108, 56,
+ 10, 50, 201, 162, 16, 27, 205, 31, 89, 17, 215, 55, 170, 31, 185,
+ 203, 190, 244, 44, 49, 10, 129, 42, 235, 111, 202, 28, 14, 87, 58,
+ 140, 172, 196, 120, 236, 29, 217, 112, 201, 185, 177, 113, 3, 232, 78,
+ 60, 63, 242, 58, 195, 17, 36, 247, 167, 232, 154, 152, 40, 29, 84,
+ 38, 138, 84, 46, 202, 156, 205, 162, 12, 211, 99, 208, 91, 244, 40,
+ 42, 218, 76, 51, 57, 130, 158, 42, 244, 229, 143, 17, 162, 233, 41,
+ 2, 70, 39, 166, 134, 15, 160, 152, 128, 31, 7, 163, 92, 140, 152,
+ 236, 103, 160, 123, 172, 227, 197, 232, 33, 138, 54, 21, 82, 214, 56,
+ 114, 107, 195, 197, 35, 250, 204, 134, 143, 17, 111, 154, 15, 167, 133,
+ 60, 50, 113, 48, 180, 5, 93, 183, 35, 211, 192, 134, 209, 200, 19,
+ 196, 122, 3, 249, 93, 132, 132, 72, 241, 150, 117, 66, 52, 221, 178,
+ 30, 70, 49, 249, 120, 126, 243, 105, 52, 191, 157, 196, 5, 57, 154,
+ 47, 32, 62, 192, 49, 124, 91, 42, 86, 29, 128, 13, 145, 52, 187,
+ 81, 3, 233, 70, 203, 56, 236, 218, 67, 250, 241, 83, 112, 63, 54,
+ 134, 66, 27, 18, 25, 103, 162, 200, 191, 114, 110, 12, 188, 51, 103,
+ 184, 120, 16, 65, 65, 117, 33, 92, 158, 53, 146, 238, 20, 136, 21,
+ 185, 188, 56, 203, 37, 58, 22, 110, 19, 253, 102, 9, 99, 196, 125,
+ 24, 78, 124, 200, 56, 247, 215, 83, 201, 68, 107, 36, 118, 112, 140,
+ 64, 7, 166, 153, 19, 32, 156, 49, 180, 225, 225, 210, 224, 156, 36,
+ 97, 222, 60, 118, 153, 252, 246, 101, 127, 186, 109, 3, 85, 238, 47,
+ 62, 153, 136, 202, 192, 114, 7, 15, 129, 88, 237, 238, 179, 49, 17,
+ 221, 36, 177, 83, 134, 56, 117, 152, 167, 244, 4, 54, 56, 85, 199,
+ 202, 117, 120, 140, 33, 141, 244, 172, 31, 162, 195, 145, 38, 140, 147,
+ 98, 50, 236, 104, 232, 18, 230, 23, 206, 140, 54, 199, 44, 97, 4,
+ 60, 238, 24, 110, 140, 89, 194, 112, 10, 216, 221, 137, 24, 51, 22,
+ 157, 59, 1, 253, 78, 48, 235, 172, 122, 119, 218, 93, 223, 157, 238,
+ 235, 54, 222, 238, 12, 8, 204, 131, 59, 26, 122, 107, 78, 247, 164,
+ 228, 106, 208, 10, 27, 102, 214, 157, 244, 160, 185, 111, 192, 179, 132,
+ 254, 217, 216, 6, 217, 8, 154, 114, 209, 50, 191, 169, 33, 242, 145,
+ 210, 205, 121, 112, 122, 189, 184, 122, 20, 89, 92, 149, 60, 233, 49,
+ 164, 251, 119, 36, 1, 143, 57, 191, 179, 38, 87, 43, 79, 210, 61,
+ 86, 79, 206, 157, 21, 160, 87, 158, 132, 168, 132, 138, 180, 188, 149,
+ 242, 228, 113, 149, 245, 36, 197, 249, 241, 164, 165, 105, 145, 51, 198,
+ 136, 254, 59, 97, 140, 232, 198, 196, 190, 147, 101, 163, 231, 213, 146,
+ 30, 243, 225, 112, 92, 178, 69, 98, 15, 137, 227, 89, 238, 88, 37,
+ 146, 60, 4, 61, 47, 224, 11, 172, 175, 116, 23, 80, 154, 42, 119,
+ 146, 227, 185, 23, 162, 167, 247, 80, 2, 88, 180, 116, 218, 203, 42,
+ 51, 99, 232, 201, 78, 140, 89, 153, 53, 218, 76, 78, 121, 152, 49,
+ 213, 160, 204, 29, 134, 64, 177, 98, 238, 0, 114, 219, 89, 100, 114,
+ 42, 32, 136, 34, 119, 231, 177, 152, 97, 253, 71, 168, 152, 138, 169,
+ 241, 207, 71, 250, 87, 3, 254, 161, 6, 254, 249, 240, 163, 31, 171,
+ 141, 127, 141, 113, 246, 99, 254, 252, 24, 200, 202, 88, 52, 107, 202,
+ 236, 224, 27, 48, 61, 40, 141, 249, 243, 151, 153, 162, 217, 110, 245,
+ 78, 22, 173, 106, 204, 22, 168, 178, 217, 65, 214, 141, 249, 169, 34,
+ 112, 101, 16, 155, 139, 171, 97, 168, 19, 200, 126, 229, 229, 106, 163,
+ 214, 32, 28, 207, 169, 136, 163, 150, 232, 207, 147, 15, 67, 78, 103,
+ 22, 129, 84, 182, 234, 28, 235, 128, 242, 53, 52, 11, 52, 253, 192,
+ 181, 97, 139, 85, 22, 148, 41, 96, 11, 24, 33, 174, 102, 155, 88,
+ 44, 107, 160, 166, 214, 27, 179, 175, 80, 47, 2, 189, 184, 128, 252,
+ 166, 232, 85, 99, 92, 101, 172, 23, 35, 140, 77, 64, 44, 21, 191,
+ 187, 69, 235, 53, 144, 26, 196, 82, 64, 157, 113, 45, 141, 193, 243,
+ 160, 55, 249, 232, 65, 24, 48, 194, 128, 86, 67, 21, 1, 132, 97,
+ 44, 27, 165, 155, 2, 163, 27, 40, 13, 184, 84, 127, 53, 242, 44,
+ 170, 6, 168, 81, 128, 178, 139, 89, 60, 80, 196, 127, 62, 104, 115,
+ 76, 204, 232, 190, 203, 80, 238, 33, 204, 229, 67, 252, 172, 98, 181,
+ 192, 215, 228, 164, 1, 190, 56, 203, 106, 86, 141, 213, 145, 231, 187,
+ 26, 171, 11, 222, 23, 156, 47, 248, 135, 193, 139, 51, 95, 13, 189,
+ 208, 200, 101, 124, 88, 117, 86, 15, 105, 119, 57, 95, 164, 235, 35,
+ 237, 46, 91, 3, 233, 71, 100, 9, 138, 229, 169, 100, 3, 126, 244,
+ 212, 241, 197, 191, 71, 121, 29, 79, 189, 26, 200, 107, 40, 73, 222,
+ 7, 61, 245, 65, 207, 125, 208, 243, 70, 188, 30, 93, 173, 9, 122,
+ 8, 84, 11, 163, 172, 129, 20, 3, 169, 192, 215, 102, 77, 48, 18,
+ 198, 71, 64, 61, 247, 67, 141, 122, 200, 171, 142, 107, 245, 65, 143,
+ 224, 90, 3, 16, 181, 216, 144, 95, 123, 76, 186, 70, 232, 141, 192,
+ 169, 81, 90, 141, 92, 186, 246, 56, 80, 31, 71, 233, 199, 129, 237,
+ 139, 35, 225, 169, 33, 3, 53, 107, 6, 106, 206, 203, 212, 100, 45,
+ 144, 83, 155, 99, 60, 14, 125, 100, 172, 37, 242, 91, 161, 124, 107,
+ 96, 182, 1, 82, 91, 92, 107, 39, 213, 105, 15, 234, 0, 234, 136,
+ 84, 53, 228, 7, 128, 239, 4, 234, 12, 234, 194, 241, 154, 35, 191,
+ 57, 80, 154, 243, 183, 227, 186, 34, 239, 9, 80, 32, 90, 169, 195,
+ 219, 96, 44, 8, 233, 96, 80, 8, 240, 187, 161, 92, 119, 80, 15,
+ 164, 123, 130, 122, 225, 122, 111, 156, 251, 128, 66, 209, 183, 48, 244,
+ 136, 230, 62, 28, 164, 149, 234, 137, 125, 110, 137, 249, 33, 60, 177,
+ 95, 52, 46, 1, 20, 129, 126, 71, 130, 162, 64, 125, 65, 253, 64,
+ 253, 65, 3, 64, 3, 65, 131, 248, 120, 154, 177, 193, 24, 97, 125,
+ 169, 63, 143, 98, 164, 67, 48, 210, 161, 160, 97, 192, 24, 46, 225,
+ 141, 0, 141, 4, 69, 131, 70, 129, 70, 131, 198, 128, 98, 64, 99,
+ 209, 143, 113, 160, 241, 232, 95, 44, 16, 27, 34, 111, 2, 104, 34,
+ 104, 18, 232, 73, 204, 216, 100, 204, 214, 20, 224, 199, 209, 27, 213,
+ 244, 198, 52, 40, 1, 125, 72, 4, 233, 81, 198, 0, 74, 2, 159,
+ 12, 74, 1, 25, 65, 83, 65, 169, 160, 52, 80, 58, 200, 132, 217,
+ 174, 203, 251, 88, 147, 153, 233, 77, 86, 208, 52, 180, 107, 5, 217,
+ 144, 103, 71, 153, 12, 80, 38, 40, 11, 121, 217, 200, 203, 193, 121,
+ 58, 159, 167, 142, 92, 63, 149, 248, 51, 184, 30, 248, 112, 201, 85,
+ 147, 198, 73, 125, 39, 189, 153, 137, 242, 179, 32, 205, 218, 188, 239,
+ 173, 88, 46, 40, 15, 229, 243, 165, 57, 126, 74, 158, 91, 31, 54,
+ 27, 52, 71, 154, 171, 17, 24, 103, 107, 62, 151, 190, 176, 74, 190,
+ 236, 105, 208, 60, 208, 124, 208, 2, 208, 66, 208, 34, 208, 51, 40,
+ 187, 24, 180, 4, 180, 84, 106, 219, 141, 187, 12, 180, 28, 180, 2,
+ 180, 18, 121, 171, 64, 171, 65, 107, 64, 79, 128, 214, 130, 214, 129,
+ 214, 131, 158, 149, 230, 102, 3, 151, 37, 245, 179, 3, 219, 136, 241,
+ 108, 66, 223, 55, 227, 250, 22, 104, 99, 83, 133, 110, 60, 199, 231,
+ 89, 13, 11, 83, 113, 174, 159, 7, 189, 0, 218, 10, 122, 17, 180,
+ 13, 180, 29, 180, 3, 229, 119, 130, 118, 41, 244, 233, 37, 208, 203,
+ 160, 221, 200, 223, 3, 122, 5, 173, 239, 149, 245, 169, 11, 159, 197,
+ 250, 60, 221, 21, 250, 43, 182, 79, 237, 22, 222, 209, 238, 62, 208,
+ 126, 208, 1, 208, 65, 208, 171, 160, 215, 64, 135, 64, 135, 65, 175,
+ 131, 142, 128, 138, 64, 197, 160, 18, 144, 3, 228, 4, 185, 64, 111,
+ 128, 142, 130, 142, 1, 251, 77, 232, 195, 113, 208, 9, 200, 227, 57,
+ 208, 91, 200, 59, 9, 122, 27, 244, 14, 232, 93, 148, 123, 15, 116,
+ 10, 244, 62, 232, 3, 122, 91, 22, 180, 7, 244, 33, 232, 35, 148,
+ 57, 13, 250, 24, 117, 63, 145, 117, 216, 61, 174, 174, 236, 12, 234,
+ 124, 10, 250, 12, 244, 57, 232, 11, 208, 151, 40, 243, 21, 168, 30,
+ 31, 247, 19, 176, 95, 226, 58, 250, 26, 244, 13, 174, 127, 43, 201,
+ 182, 57, 95, 245, 180, 62, 130, 96, 179, 130, 248, 202, 87, 73, 50,
+ 41, 148, 202, 148, 221, 97, 75, 191, 3, 125, 15, 250, 1, 244, 35,
+ 232, 39, 208, 207, 160, 39, 64, 191, 112, 157, 246, 133, 191, 243, 101,
+ 191, 193, 18, 136, 235, 63, 132, 253, 14, 59, 114, 22, 116, 78, 234,
+ 243, 31, 18, 246, 159, 40, 111, 64, 217, 243, 124, 189, 249, 194, 151,
+ 249, 178, 139, 160, 191, 64, 127, 195, 242, 144, 13, 254, 7, 116, 9,
+ 101, 47, 131, 174, 128, 174, 162, 151, 215, 232, 5, 111, 208, 191, 160,
+ 27, 176, 78, 212, 183, 155, 82, 185, 91, 160, 107, 160, 27, 176, 88,
+ 245, 65, 12, 228, 30, 211, 109, 158, 47, 182, 205, 84, 106, 166, 2,
+ 169, 65, 26, 144, 15, 168, 26, 168, 58, 200, 87, 5, 31, 0, 170,
+ 169, 234, 206, 30, 82, 117, 99, 181, 84, 61, 177, 226, 60, 99, 169,
+ 173, 162, 177, 180, 99, 117, 84, 237, 88, 93, 21, 141, 169, 23, 123,
+ 88, 5, 47, 172, 162, 177, 213, 98, 245, 80, 183, 190, 74, 57, 46,
+ 31, 110, 75, 30, 81, 209, 152, 197, 246, 27, 224, 250, 163, 160, 134,
+ 160, 70, 138, 126, 208, 90, 234, 6, 34, 95, 208, 24, 215, 154, 128,
+ 30, 3, 61, 14, 106, 10, 106, 6, 106, 14, 195, 221, 2, 228, 175,
+ 122, 130, 181, 84, 245, 70, 191, 122, 115, 171, 172, 98, 238, 254, 54,
+ 98, 173, 64, 173, 85, 162, 175, 105, 131, 115, 91, 80, 59, 80, 123,
+ 80, 7, 149, 91, 254, 110, 31, 231, 195, 58, 170, 200, 159, 244, 129,
+ 174, 104, 88, 128, 74, 195, 58, 129, 58, 131, 186, 160, 157, 174, 160,
+ 219, 104, 225, 9, 156, 253, 96, 245, 201, 103, 6, 168, 124, 80, 198,
+ 7, 101, 124, 42, 41, 19, 198, 113, 3, 113, 45, 8, 109, 5, 243,
+ 60, 198, 66, 84, 226, 90, 239, 166, 18, 125, 68, 119, 85, 77, 214,
+ 67, 21, 206, 125, 126, 79, 180, 223, 75, 165, 133, 62, 10, 72, 135,
+ 179, 222, 40, 211, 7, 20, 138, 216, 132, 244, 47, 76, 129, 115, 27,
+ 43, 222, 7, 231, 25, 160, 100, 250, 210, 0, 100, 132, 5, 32, 31,
+ 26, 174, 234, 139, 113, 121, 100, 165, 85, 185, 245, 206, 45, 159, 154,
+ 76, 64, 187, 17, 160, 72, 96, 71, 169, 4, 214, 87, 21, 201, 250,
+ 169, 162, 88, 127, 212, 29, 192, 101, 215, 143, 13, 196, 245, 65, 104,
+ 191, 29, 104, 176, 234, 78, 61, 85, 179, 33, 210, 28, 14, 229, 50,
+ 245, 101, 195, 80, 111, 184, 170, 191, 228, 67, 61, 250, 53, 130, 151,
+ 99, 108, 36, 250, 30, 13, 26, 5, 106, 198, 215, 73, 119, 54, 90,
+ 229, 238, 215, 0, 30, 35, 145, 157, 31, 195, 231, 166, 29, 139, 81,
+ 13, 68, 222, 64, 122, 231, 157, 251, 233, 177, 42, 242, 169, 237, 96,
+ 203, 61, 118, 115, 28, 202, 142, 7, 197, 130, 38, 160, 208, 68, 232,
+ 227, 36, 208, 147, 178, 78, 210, 28, 12, 98, 147, 85, 131, 217, 20,
+ 94, 95, 156, 143, 56, 62, 39, 181, 88, 60, 159, 143, 33, 76, 39,
+ 233, 106, 2, 206, 137, 42, 113, 140, 122, 149, 184, 30, 13, 56, 39,
+ 129, 146, 65, 41, 32, 163, 202, 151, 199, 142, 110, 251, 48, 21, 237,
+ 166, 130, 210, 64, 233, 32, 19, 198, 107, 6, 89, 64, 211, 64, 86,
+ 144, 13, 100, 7, 101, 128, 50, 81, 63, 11, 148, 13, 202, 1, 77,
+ 7, 205, 0, 205, 4, 205, 2, 229, 130, 242, 128, 147, 15, 122, 10,
+ 244, 39, 198, 62, 91, 69, 118, 172, 22, 155, 131, 126, 207, 5, 61,
+ 13, 154, 199, 229, 51, 128, 205, 7, 45, 64, 157, 133, 192, 94, 4,
+ 122, 6, 124, 16, 230, 99, 49, 104, 137, 74, 180, 71, 75, 81, 126,
+ 153, 106, 40, 188, 143, 199, 230, 23, 72, 62, 98, 57, 202, 175, 0,
+ 173, 4, 173, 2, 173, 6, 173, 1, 173, 5, 173, 3, 173, 87, 137,
+ 118, 255, 117, 201, 246, 63, 11, 204, 13, 200, 219, 8, 218, 4, 218,
+ 140, 54, 183, 112, 189, 246, 101, 207, 33, 93, 0, 122, 30, 244, 2,
+ 104, 43, 232, 69, 208, 54, 208, 118, 208, 14, 208, 78, 208, 46, 208,
+ 75, 168, 243, 50, 104, 55, 104, 15, 232, 21, 21, 217, 119, 146, 27,
+ 217, 118, 26, 239, 48, 62, 191, 123, 113, 173, 16, 180, 79, 210, 183,
+ 253, 56, 31, 0, 29, 4, 189, 10, 122, 13, 116, 8, 116, 24, 244,
+ 58, 48, 142, 0, 187, 8, 84, 12, 42, 81, 13, 199, 90, 29, 142,
+ 25, 28, 14, 29, 34, 153, 249, 192, 158, 251, 112, 28, 7, 202, 59,
+ 85, 20, 71, 140, 224, 54, 199, 165, 18, 125, 247, 27, 56, 31, 5,
+ 29, 227, 237, 137, 114, 122, 19, 116, 28, 116, 2, 244, 22, 232, 36,
+ 174, 189, 13, 122, 7, 244, 46, 232, 61, 80, 56, 234, 158, 194, 249,
+ 125, 208, 7, 160, 82, 208, 135, 160, 143, 64, 167, 97, 139, 62, 6,
+ 125, 2, 254, 12, 232, 83, 208, 103, 160, 207, 65, 95, 128, 190, 148,
+ 236, 194, 87, 56, 127, 13, 250, 6, 244, 45, 168, 140, 143, 1, 62,
+ 7, 244, 61, 232, 7, 208, 143, 208, 137, 159, 64, 63, 131, 126, 1,
+ 253, 170, 26, 201, 119, 63, 245, 177, 54, 126, 131, 140, 127, 71, 250,
+ 172, 138, 98, 14, 232, 56, 198, 255, 135, 42, 154, 253, 73, 250, 173,
+ 162, 241, 143, 98, 23, 160, 55, 23, 85, 195, 216, 95, 92, 127, 70,
+ 192, 126, 208, 92, 143, 134, 189, 162, 58, 20, 15, 186, 109, 44, 108,
+ 9, 249, 33, 156, 255, 65, 95, 46, 129, 46, 3, 227, 138, 106, 12,
+ 34, 153, 49, 244, 93, 9, 159, 211, 171, 184, 126, 13, 116, 29, 244,
+ 47, 232, 6, 232, 38, 201, 159, 124, 17, 234, 220, 150, 100, 199, 212,
+ 226, 252, 171, 212, 176, 245, 32, 13, 200, 71, 45, 206, 49, 197, 191,
+ 213, 212, 240, 175, 32, 95, 181, 24, 127, 158, 87, 209, 120, 176, 51,
+ 66, 153, 154, 160, 135, 64, 181, 64, 181, 65, 117, 64, 117, 65, 15,
+ 83, 125, 80, 61, 80, 125, 208, 35, 168, 219, 0, 244, 168, 122, 52,
+ 107, 168, 30, 195, 26, 169, 99, 96, 143, 26, 193, 174, 208, 190, 163,
+ 33, 107, 172, 110, 200, 154, 128, 30, 67, 153, 199, 65, 77, 65, 205,
+ 64, 205, 81, 183, 5, 200, 31, 212, 18, 212, 74, 61, 22, 241, 192,
+ 88, 178, 58, 210, 24, 125, 88, 107, 96, 181, 81, 215, 100, 109, 213,
+ 181, 88, 59, 181, 103, 207, 209, 30, 229, 59, 128, 58, 130, 2, 212,
+ 180, 175, 17, 125, 78, 39, 240, 157, 213, 62, 124, 127, 20, 170, 162,
+ 62, 140, 67, 140, 60, 14, 152, 227, 36, 76, 236, 71, 80, 166, 43,
+ 199, 133, 223, 83, 139, 117, 8, 43, 16, 237, 4, 225, 28, 140, 105,
+ 11, 1, 117, 3, 223, 29, 212, 67, 77, 243, 175, 102, 61, 193, 247,
+ 2, 245, 86, 147, 157, 25, 15, 29, 31, 15, 220, 241, 114, 95, 63,
+ 97, 30, 204, 191, 201, 143, 168, 99, 209, 126, 44, 202, 196, 202, 101,
+ 234, 33, 146, 10, 5, 94, 24, 240, 195, 65, 90, 144, 160, 22, 237,
+ 106, 132, 90, 92, 107, 145, 56, 71, 129, 250, 226, 90, 63, 156, 251,
+ 171, 41, 6, 87, 179, 1, 56, 15, 68, 31, 7, 225, 60, 88, 61,
+ 17, 154, 54, 17, 216, 19, 21, 216, 212, 126, 45, 54, 68, 26, 207,
+ 80, 181, 219, 223, 210, 184, 38, 129, 159, 132, 242, 147, 238, 40, 223,
+ 138, 13, 83, 139, 250, 214, 71, 45, 174, 7, 170, 59, 28, 52, 130,
+ 250, 133, 113, 55, 151, 108, 64, 103, 245, 147, 168, 243, 36, 48, 158,
+ 148, 49, 70, 170, 91, 176, 104, 140, 103, 20, 104, 52, 205, 29, 151,
+ 129, 15, 27, 3, 138, 1, 238, 88, 200, 125, 28, 104, 60, 250, 29,
+ 11, 154, 0, 154, 168, 158, 44, 237, 97, 177, 39, 66, 185, 39, 49,
+ 206, 201, 160, 41, 160, 56, 80, 60, 72, 7, 74, 0, 37, 130, 244,
+ 192, 53, 168, 197, 125, 105, 18, 202, 207, 82, 77, 65, 63, 196, 189,
+ 109, 50, 198, 155, 2, 50, 170, 71, 178, 169, 40, 147, 10, 74, 3,
+ 165, 131, 76, 32, 51, 201, 10, 52, 13, 100, 5, 217, 56, 14, 252,
+ 2, 206, 25, 234, 56, 196, 112, 113, 124, 39, 166, 2, 101, 170, 107,
+ 179, 44, 174, 59, 241, 88, 9, 241, 124, 119, 70, 249, 217, 40, 151,
+ 131, 242, 159, 168, 220, 251, 110, 29, 116, 80, 199, 119, 110, 158, 235,
+ 113, 108, 58, 104, 134, 122, 10, 155, 137, 178, 179, 64, 185, 160, 60,
+ 80, 62, 230, 225, 41, 204, 65, 107, 85, 67, 54, 27, 231, 57, 200,
+ 155, 11, 122, 26, 52, 15, 227, 187, 10, 123, 50, 31, 252, 2, 208,
+ 66, 164, 23, 129, 158, 1, 45, 6, 45, 65, 222, 82, 208, 50, 208,
+ 114, 181, 40, 203, 21, 152, 195, 149, 160, 85, 160, 213, 160, 53, 160,
+ 181, 152, 131, 117, 160, 245, 234, 4, 126, 103, 225, 89, 148, 221, 160,
+ 38, 187, 231, 195, 54, 170, 19, 249, 157, 166, 77, 106, 218, 203, 38,
+ 178, 205, 72, 111, 1, 61, 167, 22, 247, 105, 5, 106, 26, 147, 30,
+ 179, 169, 71, 41, 61, 143, 91, 155, 75, 251, 43, 146, 211, 243, 40,
+ 251, 2, 250, 178, 21, 229, 95, 4, 109, 227, 229, 13, 252, 206, 203,
+ 118, 181, 123, 255, 73, 251, 78, 218, 95, 138, 123, 79, 113, 223, 89,
+ 83, 218, 119, 38, 33, 218, 79, 162, 111, 11, 129, 157, 196, 118, 160,
+ 142, 251, 94, 134, 184, 215, 19, 239, 5, 236, 4, 238, 46, 208, 75,
+ 160, 151, 65, 187, 65, 123, 64, 175, 128, 246, 146, 29, 195, 60, 238,
+ 3, 237, 7, 191, 30, 253, 60, 128, 126, 29, 228, 54, 129, 100, 79,
+ 123, 117, 236, 153, 112, 253, 53, 181, 1, 251, 190, 36, 118, 72, 157,
+ 196, 14, 131, 94, 199, 188, 28, 81, 39, 99, 31, 81, 139, 21, 113,
+ 190, 22, 43, 150, 215, 6, 141, 37, 5, 215, 82, 120, 68, 167, 82,
+ 220, 55, 40, 225, 243, 109, 196, 220, 25, 121, 164, 87, 241, 154, 184,
+ 255, 88, 143, 29, 99, 11, 16, 3, 221, 89, 134, 246, 176, 14, 244,
+ 201, 9, 114, 161, 223, 111, 128, 218, 163, 205, 163, 72, 31, 3, 189,
+ 9, 58, 14, 58, 1, 122, 11, 116, 18, 244, 54, 232, 29, 208, 187,
+ 160, 247, 64, 167, 64, 239, 3, 235, 3, 80, 41, 232, 67, 208, 71,
+ 160, 211, 100, 131, 89, 42, 251, 88, 157, 134, 246, 210, 232, 219, 240,
+ 74, 219, 79, 69, 253, 116, 208, 39, 106, 49, 246, 63, 131, 243, 167,
+ 160, 207, 164, 182, 62, 231, 125, 75, 135, 76, 218, 177, 47, 164, 121,
+ 41, 31, 227, 81, 236, 133, 253, 29, 202, 125, 5, 250, 26, 244, 141,
+ 90, 220, 31, 215, 99, 38, 72, 216, 132, 182, 77, 60, 14, 166, 249,
+ 248, 86, 186, 78, 123, 211, 50, 181, 47, 143, 133, 190, 83, 155, 185,
+ 55, 168, 207, 177, 197, 54, 190, 71, 91, 63, 64, 22, 63, 162, 204,
+ 79, 160, 159, 65, 191, 128, 126, 5, 253, 6, 250, 29, 116, 22, 116,
+ 142, 203, 152, 98, 76, 101, 159, 124, 216, 31, 232, 243, 104, 156, 255,
+ 196, 156, 158, 87, 91, 88, 109, 126, 23, 196, 82, 110, 14, 242, 85,
+ 180, 247, 242, 236, 37, 47, 0, 239, 162, 186, 49, 251, 11, 237, 254,
+ 173, 158, 134, 40, 100, 26, 191, 115, 34, 218, 51, 178, 201, 62, 236,
+ 31, 201, 14, 94, 194, 249, 50, 232, 138, 218, 227, 15, 175, 130, 174,
+ 129, 174, 131, 254, 5, 221, 0, 221, 4, 221, 2, 221, 6, 193, 193,
+ 50, 21, 72, 13, 210, 128, 124, 64, 213, 64, 213, 65, 190, 160, 26,
+ 160, 154, 160, 135, 64, 181, 64, 181, 65, 117, 64, 117, 65, 15, 131,
+ 252, 64, 245, 64, 245, 65, 143, 128, 26, 128, 30, 5, 53, 4, 53,
+ 2, 53, 6, 53, 1, 61, 6, 122, 28, 212, 20, 212, 12, 212, 28,
+ 212, 2, 228, 15, 106, 169, 97, 172, 21, 168, 53, 168, 13, 168, 173,
+ 198, 202, 218, 129, 218, 107, 124, 88, 7, 80, 71, 80, 0, 168, 19,
+ 168, 179, 198, 151, 117, 1, 117, 5, 61, 129, 186, 129, 160, 32, 80,
+ 48, 40, 68, 99, 99, 221, 64, 221, 193, 247, 0, 245, 212, 208, 90,
+ 105, 195, 122, 105, 200, 7, 217, 177, 154, 232, 99, 89, 187, 180, 79,
+ 16, 231, 188, 55, 202, 244, 1, 133, 106, 196, 249, 167, 253, 86, 24,
+ 202, 135, 107, 50, 48, 255, 84, 78, 212, 27, 45, 202, 8, 28, 47,
+ 147, 239, 65, 220, 242, 162, 123, 13, 125, 212, 89, 124, 159, 53, 22,
+ 251, 132, 8, 141, 91, 207, 178, 177, 70, 225, 27, 129, 27, 165, 17,
+ 203, 247, 197, 216, 250, 129, 250, 107, 114, 248, 189, 64, 113, 127, 67,
+ 245, 24, 27, 128, 252, 129, 154, 233, 168, 35, 166, 7, 161, 206, 96,
+ 208, 219, 146, 108, 251, 168, 103, 200, 253, 25, 130, 54, 134, 74, 253,
+ 29, 166, 153, 201, 191, 114, 31, 171, 162, 53, 234, 195, 134, 107, 102,
+ 49, 95, 169, 220, 80, 92, 24, 1, 26, 169, 17, 49, 62, 65, 123,
+ 209, 154, 92, 148, 111, 199, 70, 33, 127, 52, 104, 140, 38, 15, 125,
+ 200, 67, 141, 60, 89, 15, 123, 75, 216, 49, 56, 143, 5, 141, 211,
+ 184, 199, 233, 222, 95, 229, 179, 241, 26, 113, 237, 197, 226, 218, 4,
+ 62, 47, 79, 241, 121, 157, 168, 153, 141, 51, 249, 216, 124, 172, 157,
+ 124, 250, 141, 3, 70, 95, 29, 79, 210, 120, 230, 236, 73, 9, 147,
+ 218, 153, 172, 81, 115, 63, 62, 69, 227, 198, 158, 3, 236, 60, 22,
+ 135, 252, 120, 144, 14, 216, 9, 154, 185, 124, 239, 155, 168, 17, 247,
+ 124, 95, 168, 159, 198, 218, 31, 196, 244, 10, 76, 7, 48, 156, 106,
+ 81, 174, 6, 228, 39, 97, 142, 146, 113, 78, 1, 133, 34, 207, 136,
+ 243, 84, 205, 60, 126, 199, 157, 202, 167, 106, 220, 117, 230, 179, 52,
+ 9, 39, 29, 103, 19, 200, 172, 89, 192, 239, 117, 39, 202, 248, 212,
+ 102, 95, 102, 209, 136, 243, 58, 13, 249, 86, 210, 123, 182, 144, 223,
+ 123, 108, 38, 223, 223, 38, 187, 78, 241, 232, 34, 46, 95, 63, 46,
+ 99, 183, 124, 9, 227, 25, 172, 121, 119, 190, 47, 179, 161, 143, 118,
+ 141, 184, 167, 188, 32, 237, 43, 105, 31, 153, 129, 188, 76, 80, 22,
+ 218, 203, 214, 44, 150, 251, 220, 236, 142, 113, 126, 34, 221, 239, 204,
+ 65, 95, 166, 107, 150, 192, 238, 83, 27, 162, 221, 156, 129, 250, 99,
+ 84, 100, 215, 220, 122, 130, 189, 163, 102, 41, 90, 17, 211, 111, 75,
+ 54, 107, 22, 242, 115, 65, 121, 160, 124, 205, 50, 254, 132, 226, 254,
+ 109, 209, 94, 97, 57, 183, 82, 164, 115, 79, 65, 46, 179, 65, 115,
+ 128, 49, 23, 244, 52, 215, 187, 21, 92, 15, 231, 97, 220, 243, 185,
+ 174, 33, 94, 208, 136, 58, 72, 122, 52, 70, 51, 7, 109, 205, 161,
+ 159, 116, 129, 126, 204, 41, 167, 31, 164, 23, 11, 53, 158, 189, 252,
+ 23, 234, 81, 252, 62, 9, 237, 131, 23, 1, 255, 25, 208, 98, 208,
+ 18, 141, 15, 223, 23, 44, 5, 191, 12, 180, 92, 67, 235, 110, 37,
+ 250, 41, 238, 115, 190, 80, 123, 48, 87, 0, 115, 37, 214, 245, 42,
+ 13, 237, 133, 17, 135, 128, 95, 163, 169, 197, 218, 171, 250, 178, 181,
+ 154, 190, 108, 29, 174, 175, 215, 136, 251, 187, 103, 53, 226, 30, 239,
+ 21, 201, 103, 210, 62, 127, 161, 74, 121, 239, 115, 8, 235, 194, 219,
+ 168, 201, 54, 160, 205, 141, 146, 12, 55, 225, 188, 25, 180, 5, 244,
+ 28, 168, 0, 244, 188, 70, 148, 237, 11, 56, 111, 213, 136, 99, 120,
+ 17, 231, 109, 160, 237, 160, 29, 154, 242, 247, 84, 119, 34, 189, 11,
+ 125, 123, 73, 211, 149, 189, 140, 185, 219, 13, 106, 135, 118, 246, 104,
+ 220, 253, 236, 203, 94, 65, 255, 246, 130, 10, 53, 140, 235, 151, 251,
+ 30, 195, 62, 169, 223, 52, 134, 253, 224, 15, 0, 235, 32, 232, 85,
+ 140, 249, 53, 62, 214, 249, 210, 30, 144, 238, 195, 175, 98, 135, 52,
+ 116, 79, 179, 38, 59, 172, 33, 127, 133, 189, 59, 202, 30, 1, 21,
+ 129, 138, 65, 37, 32, 7, 200, 169, 161, 231, 21, 140, 185, 208, 222,
+ 27, 154, 213, 210, 115, 26, 95, 118, 20, 215, 142, 129, 222, 68, 91,
+ 199, 65, 39, 52, 107, 176, 46, 215, 160, 228, 154, 59, 98, 118, 113,
+ 141, 61, 39, 173, 187, 242, 49, 58, 233, 195, 90, 96, 174, 69, 189,
+ 181, 220, 6, 137, 251, 107, 248, 120, 21, 233, 192, 186, 255, 235, 236,
+ 92, 114, 26, 134, 129, 48, 236, 104, 186, 235, 138, 75, 112, 6, 164,
+ 74, 89, 32, 144, 96, 211, 75, 32, 245, 58, 221, 181, 168, 105, 120,
+ 174, 56, 73, 161, 45, 239, 247, 155, 2, 226, 28, 124, 191, 39, 9,
+ 1, 177, 234, 98, 148, 100, 60, 246, 216, 227, 177, 199, 254, 103, 17,
+ 124, 160, 79, 89, 159, 178, 94, 24, 153, 199, 227, 133, 80, 143, 173,
+ 117, 60, 103, 30, 140, 230, 47, 54, 243, 131, 189, 28, 216, 102, 208,
+ 233, 45, 64, 73, 244, 169, 102, 56, 196, 255, 27, 197, 121, 254, 8,
+ 187, 142, 173, 23, 38, 150, 114, 119, 74, 145, 75, 145, 75, 233, 79,
+ 51, 76, 139, 253, 226, 24, 27, 157, 64, 167, 133, 191, 42, 62, 44,
+ 213, 176, 164, 178, 143, 245, 190, 157, 33, 127, 14, 93, 64, 151, 166,
+ 76, 129, 235, 187, 66, 223, 181, 249, 30, 114, 195, 243, 22, 186, 179,
+ 1, 235, 99, 160, 223, 139, 196, 188, 98, 55, 113, 61, 37, 14, 215,
+ 137, 109, 122, 140, 104, 37, 235, 81, 230, 222, 50, 74, 50, 234, 100,
+ 124, 203, 110, 101, 189, 82, 110, 173, 26, 163, 100, 31, 208, 241, 104,
+ 67, 244, 40, 127, 58, 172, 238, 166, 79, 166, 57, 212, 28, 11, 63,
+ 115, 204, 68, 247, 177, 86, 146, 227, 11, 57, 178, 57, 178, 90, 199,
+ 210, 225, 254, 234, 241, 197, 109, 243, 204, 248, 54, 160, 23, 232, 21,
+ 122, 179, 45, 90, 94, 12, 51, 222, 223, 25, 219, 7, 54, 252, 180,
+ 237, 130, 167, 126, 53, 216, 203, 197, 219, 169, 120, 126, 119, 22, 111,
+ 247, 31, 222, 94, 156, 183, 153, 237, 71, 92, 254, 119, 206, 146, 115,
+ 28, 122, 190, 108, 181, 189, 178, 172, 60, 240, 55, 121, 216, 88, 60, };
+
+ *dataSize = 138801;
+
+ // allocate a new array
+ *data = new unsigned char[138801];
+ // and copy it. Now we are certain that the calling function
+ // can control the memory location
+ for(int i = 0; i < 138801 /* tmp array size */; i++)
+ {
+ (*data)[i] = load_blend[i];
+ }
+
+}
+
+
+
diff --git a/source/gameengine/GamePlayer/common/GPC_RawLoadDotBlendArray.h b/source/gameengine/GamePlayer/common/GPC_RawLoadDotBlendArray.h
new file mode 100644
index 00000000000..05b7e3d9c3a
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_RawLoadDotBlendArray.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 __GPC_RAWLOADDOTBLENDARRAY_H
+#define __GPC_RAWLOADDOTBLENDARRAY_H
+
+void GetRawLoadingAnimation(unsigned char **data, int *dataSize);
+
+#endif // __GPC_RAWLOADDOTBLENDARRAY_H
+
diff --git a/source/gameengine/GamePlayer/common/GPC_RawLogoArrays.cpp b/source/gameengine/GamePlayer/common/GPC_RawLogoArrays.cpp
new file mode 100644
index 00000000000..955a644513a
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_RawLogoArrays.cpp
@@ -0,0 +1,1463 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 is automatically generated. Do not edit by hand!
+
+#include "GPC_RawLogoArrays.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void GetRawBlenderLogo(unsigned char **data, int *width, int *height)
+{
+ // create an array that will automatically be deleted when)
+ // we're outta this scope
+ static unsigned char logo_blender_raw[]= { 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 20, 20, 21, 44, 44, 44,
+ 45, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 12, 124,
+ 124, 124, 124, 232, 232, 232, 232, 248, 248, 248, 248, 243, 243, 243, 243,
+ 160, 160, 160, 160, 44, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 13, 13, 13, 13, 172, 172, 172, 173, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 235,
+ 235, 235, 235, 95, 95, 95, 95, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 88, 88, 88,
+ 255, 255, 255, 255, 255, 255, 255, 255, 254, 235, 217, 255, 253, 202, 152,
+ 255, 253, 216, 183, 255, 255, 250, 246, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 155, 155, 155, 155, 20, 20, 20, 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, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 128, 128, 128, 255, 255, 255, 255, 255,
+ 249, 245, 255, 250, 162, 78, 255, 250, 145, 40, 255, 250, 149, 49, 255,
+ 251, 175, 104, 255, 254, 236, 219, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 202, 202, 202, 203, 53, 53, 53, 53, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 113, 113, 113, 113, 255, 255, 255, 255, 255, 253, 253, 255, 251, 196,
+ 147, 255, 249, 150, 51, 255, 249, 152, 55, 255, 248, 149, 50, 255, 249,
+ 160, 74, 255, 253, 219, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 236, 236, 236, 236, 90, 90, 90, 90, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 76, 76,
+ 76, 76, 120, 120, 120, 120, 138, 138, 138, 138, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 163, 163, 163, 164, 196, 196, 196, 198,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 252, 206, 166,
+ 255, 248, 153, 61, 255, 247, 149, 52, 255, 247, 150, 53, 255, 247, 150,
+ 54, 255, 251, 196, 150, 255, 255, 249, 246, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 143, 143, 143, 143, 14, 14, 14, 14, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 43, 43, 43, 42, 198, 198, 198, 199, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 226, 203, 255,
+ 248, 165, 85, 255, 246, 150, 53, 255, 246, 151, 55, 255, 246, 145, 46,
+ 255, 248, 175, 106, 255, 253, 238, 226, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 189, 189, 189, 189, 39, 39, 39, 39, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 22, 22, 22, 22, 214, 214, 214, 216, 255,
+ 255, 255, 255, 255, 255, 255, 255, 252, 245, 238, 255, 251, 233, 218, 255,
+ 251, 231, 215, 255, 251, 232, 216, 255, 251, 232, 216, 255, 252, 232, 216,
+ 255, 252, 232, 216, 255, 252, 232, 216, 255, 252, 232, 216, 255, 252, 232,
+ 216, 255, 252, 232, 217, 255, 252, 236, 223, 255, 251, 214, 186, 255, 245,
+ 156, 72, 255, 245, 150, 54, 255, 245, 151, 56, 255, 245, 146, 48, 255,
+ 246, 159, 76, 255, 252, 223, 198, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 226, 226, 226, 226, 71, 71, 71, 71, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 93, 93, 93, 93, 255, 255, 255, 255, 253, 253, 252, 255, 248, 209,
+ 173, 255, 244, 155, 66, 255, 244, 152, 62, 255, 245, 152, 62, 255, 245,
+ 153, 62, 255, 245, 153, 62, 255, 245, 152, 62, 255, 245, 152, 62, 255,
+ 245, 152, 62, 255, 245, 152, 62, 255, 245, 152, 62, 255, 245, 152, 62,
+ 255, 245, 153, 62, 255, 245, 155, 66, 255, 244, 152, 62, 255, 244, 150,
+ 56, 255, 244, 150, 57, 255, 244, 150, 56, 255, 243, 146, 49, 255, 243,
+ 147, 54, 255, 249, 203, 162, 255, 254, 253, 254, 255, 255, 255, 255, 255,
+ 248, 248, 248, 248, 143, 143, 143, 143, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 119, 119, 119, 120, 119,
+ 119, 119, 120, 119, 119, 119, 120, 119, 119, 119, 120, 119, 119, 119, 120,
+ 119, 119, 119, 120, 119, 119, 119, 120, 119, 119, 119, 120, 119, 119, 119,
+ 120, 119, 119, 119, 120, 119, 119, 119, 120, 119, 119, 119, 120, 119, 119,
+ 119, 120, 119, 119, 119, 120, 119, 119, 119, 120, 119, 119, 119, 120, 119,
+ 119, 119, 120, 119, 119, 119, 120, 119, 119, 119, 120, 118, 118, 118, 120,
+ 118, 118, 118, 120, 118, 118, 118, 120, 118, 118, 118, 120, 118, 118, 118,
+ 120, 118, 118, 118, 119, 118, 118, 118, 119, 118, 118, 118, 120, 118, 118,
+ 118, 119, 111, 111, 111, 112, 75, 75, 75, 75, 20, 20, 20, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 125, 125, 126,
+ 255, 255, 255, 255, 250, 242, 234, 255, 242, 149, 57, 255, 242, 142, 42,
+ 255, 243, 146, 48, 255, 243, 146, 48, 255, 243, 146, 48, 255, 243, 145,
+ 48, 255, 243, 145, 48, 255, 243, 147, 51, 255, 244, 149, 55, 255, 244,
+ 149, 55, 255, 243, 149, 54, 255, 243, 149, 54, 255, 243, 149, 55, 255,
+ 243, 148, 52, 255, 243, 146, 49, 255, 243, 146, 49, 255, 243, 146, 49,
+ 255, 243, 147, 52, 255, 242, 149, 55, 255, 242, 147, 52, 255, 241, 142,
+ 45, 255, 246, 181, 122, 255, 252, 244, 238, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 223, 223, 223, 223, 102, 102, 102, 102, 12, 12,
+ 12, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 109, 109, 109, 110, 255, 255, 255, 255, 251,
+ 251, 250, 255, 245, 194, 149, 255, 243, 166, 90, 255, 243, 167, 95, 255,
+ 243, 168, 96, 255, 243, 168, 96, 255, 244, 168, 96, 255, 244, 173, 105,
+ 255, 244, 164, 89, 255, 242, 148, 55, 255, 242, 149, 56, 255, 242, 149,
+ 56, 255, 242, 148, 54, 255, 241, 143, 46, 255, 242, 149, 58, 255, 244,
+ 165, 90, 255, 244, 172, 102, 255, 244, 169, 96, 255, 242, 154, 69, 255,
+ 241, 142, 45, 255, 241, 146, 50, 255, 241, 147, 54, 255, 240, 141, 42,
+ 255, 243, 166, 94, 255, 251, 237, 226, 255, 254, 255, 255, 255, 253, 253,
+ 253, 255, 253, 253, 253, 255, 254, 254, 254, 255, 225, 232, 238, 255, 215,
+ 224, 231, 255, 246, 247, 249, 255, 255, 254, 254, 255, 253, 253, 253, 255,
+ 253, 253, 253, 255, 253, 253, 253, 255, 253, 253, 253, 255, 253, 253, 253,
+ 255, 253, 253, 253, 255, 253, 253, 253, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 254, 254, 254, 255, 253, 253, 253, 255, 253,
+ 253, 253, 255, 253, 253, 253, 255, 253, 253, 253, 255, 253, 253, 253, 255,
+ 253, 253, 253, 255, 253, 253, 253, 255, 253, 253, 253, 255, 253, 253, 253,
+ 255, 253, 253, 253, 255, 253, 253, 253, 255, 253, 253, 253, 255, 253, 253,
+ 253, 255, 253, 253, 253, 255, 253, 253, 253, 255, 253, 253, 253, 255, 253,
+ 253, 253, 255, 253, 253, 253, 255, 253, 253, 253, 255, 253, 253, 253, 255,
+ 253, 253, 253, 255, 253, 253, 253, 255, 253, 253, 253, 255, 253, 253, 253,
+ 255, 252, 252, 252, 255, 252, 252, 252, 255, 252, 252, 252, 255, 253, 253,
+ 253, 255, 255, 254, 253, 255, 244, 246, 247, 255, 208, 220, 229, 255, 234,
+ 238, 241, 255, 253, 253, 253, 255, 252, 252, 252, 255, 251, 251, 251, 255,
+ 251, 251, 251, 255, 251, 251, 251, 255, 251, 251, 251, 255, 251, 251, 251,
+ 255, 251, 251, 251, 255, 251, 251, 251, 255, 250, 250, 250, 255, 250, 250,
+ 250, 255, 250, 250, 250, 255, 250, 250, 250, 255, 250, 250, 250, 255, 250,
+ 250, 250, 255, 249, 249, 249, 255, 249, 249, 249, 255, 253, 253, 252, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 184, 183, 183, 182, 25, 25, 25,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 45, 45, 45, 45, 244, 244, 244, 248, 255, 255, 255, 255, 250, 252,
+ 254, 255, 250, 247, 246, 255, 250, 248, 246, 255, 250, 248, 246, 255, 250,
+ 249, 248, 255, 251, 254, 255, 255, 249, 230, 214, 255, 243, 167, 95, 255,
+ 241, 145, 50, 255, 241, 148, 56, 255, 241, 145, 51, 255, 241, 148, 56,
+ 255, 245, 182, 123, 255, 249, 227, 209, 255, 255, 253, 250, 255, 255, 255,
+ 254, 255, 255, 255, 254, 255, 253, 241, 232, 255, 246, 195, 152, 255, 241,
+ 155, 72, 255, 240, 142, 45, 255, 240, 147, 54, 255, 240, 141, 43, 255,
+ 242, 161, 86, 255, 250, 233, 222, 255, 252, 255, 255, 255, 252, 252, 253,
+ 255, 255, 255, 255, 255, 154, 181, 201, 255, 8, 78, 129, 255, 70, 124,
+ 161, 255, 249, 249, 250, 255, 255, 255, 254, 255, 253, 253, 253, 255, 253,
+ 253, 253, 255, 253, 253, 253, 255, 253, 253, 253, 255, 253, 253, 253, 255,
+ 254, 254, 254, 255, 213, 226, 233, 255, 119, 159, 186, 255, 127, 167, 191,
+ 255, 245, 247, 249, 255, 254, 254, 254, 255, 252, 252, 253, 255, 252, 252,
+ 252, 255, 253, 253, 253, 255, 255, 255, 254, 255, 255, 254, 254, 255, 253,
+ 253, 253, 255, 252, 252, 252, 255, 253, 253, 253, 255, 253, 253, 253, 255,
+ 253, 253, 253, 255, 252, 252, 252, 255, 252, 252, 252, 255, 252, 252, 252,
+ 255, 252, 252, 252, 255, 252, 252, 252, 255, 253, 253, 253, 255, 252, 252,
+ 252, 255, 252, 252, 252, 255, 252, 252, 252, 255, 252, 252, 252, 255, 252,
+ 252, 252, 255, 252, 252, 252, 255, 252, 252, 252, 255, 252, 252, 252, 255,
+ 252, 252, 252, 255, 252, 252, 252, 255, 255, 255, 255, 255, 206, 218, 228,
+ 255, 38, 105, 148, 255, 13, 91, 139, 255, 202, 213, 222, 255, 255, 255,
+ 255, 255, 251, 251, 251, 255, 251, 251, 251, 255, 251, 251, 251, 255, 253,
+ 252, 252, 255, 253, 252, 252, 255, 251, 251, 251, 255, 250, 250, 250, 255,
+ 250, 250, 250, 255, 250, 250, 250, 255, 250, 250, 250, 255, 249, 249, 249,
+ 255, 249, 249, 249, 255, 249, 249, 249, 255, 249, 249, 249, 255, 250, 250,
+ 249, 255, 252, 252, 251, 255, 228, 232, 236, 255, 198, 210, 220, 255, 226,
+ 229, 234, 255, 239, 244, 249, 255, 179, 181, 183, 190, 15, 15, 14, 13,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 94, 94, 94, 94, 220, 220, 220, 220, 250, 251, 251, 254, 250, 251, 252,
+ 255, 250, 251, 252, 255, 250, 253, 255, 255, 250, 255, 255, 255, 246, 216,
+ 188, 255, 241, 151, 62, 255, 240, 144, 49, 255, 240, 148, 56, 255, 240,
+ 145, 50, 255, 240, 149, 59, 255, 247, 214, 184, 255, 254, 255, 255, 255,
+ 255, 255, 255, 255, 238, 241, 245, 255, 210, 220, 230, 255, 215, 224, 232,
+ 255, 249, 252, 254, 255, 255, 255, 255, 255, 249, 234, 222, 255, 241, 165,
+ 94, 255, 239, 142, 44, 255, 239, 146, 53, 255, 238, 141, 44, 255, 240,
+ 156, 78, 255, 250, 237, 226, 255, 252, 255, 255, 255, 255, 255, 255, 255,
+ 154, 181, 201, 255, 0, 71, 125, 255, 29, 98, 142, 255, 246, 246, 248,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 252, 252, 252, 255, 255, 255, 255, 255, 173,
+ 199, 214, 255, 0, 68, 122, 255, 0, 83, 132, 255, 236, 241, 244, 255,
+ 255, 255, 254, 255, 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 251, 248, 248, 255, 254, 250, 250, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 254, 253, 255, 252, 252, 252, 255, 253, 253, 253, 255, 255,
+ 255, 254, 255, 255, 255, 254, 255, 253, 253, 252, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 253, 253, 252, 255, 251, 251, 251, 255, 251, 251, 251, 255, 253, 252,
+ 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 177, 201, 216, 255, 0, 81, 132, 255,
+ 7, 86, 136, 255, 203, 213, 222, 255, 255, 255, 255, 255, 251, 251, 251,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 249, 247, 247, 255, 248, 246,
+ 246, 255, 255, 255, 253, 255, 255, 255, 255, 255, 252, 251, 251, 255, 249,
+ 249, 249, 255, 249, 249, 249, 255, 251, 251, 250, 255, 251, 250, 250, 255,
+ 251, 250, 249, 255, 255, 255, 254, 255, 255, 251, 250, 255, 253, 251, 249,
+ 255, 218, 225, 231, 255, 155, 174, 193, 255, 175, 186, 200, 255, 170, 184,
+ 200, 255, 240, 244, 248, 255, 134, 133, 133, 133, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,
+ 56, 56, 57, 237, 237, 237, 239, 252, 252, 252, 255, 249, 254, 255, 255,
+ 249, 247, 246, 255, 243, 191, 141, 255, 239, 144, 50, 255, 239, 144, 50,
+ 255, 239, 147, 55, 255, 239, 146, 52, 255, 239, 146, 55, 255, 246, 214,
+ 185, 255, 253, 255, 255, 255, 252, 253, 254, 255, 156, 184, 203, 255, 38,
+ 103, 146, 255, 11, 89, 137, 255, 11, 87, 136, 255, 65, 123, 160, 255,
+ 199, 214, 225, 255, 255, 255, 255, 255, 250, 238, 229, 255, 239, 159, 82,
+ 255, 237, 142, 47, 255, 238, 145, 52, 255, 236, 137, 37, 255, 244, 193,
+ 145, 255, 251, 255, 255, 255, 255, 255, 255, 255, 154, 181, 201, 255, 0,
+ 73, 126, 255, 41, 105, 147, 255, 227, 231, 236, 255, 176, 198, 212, 255,
+ 134, 170, 194, 255, 120, 161, 187, 255, 151, 178, 198, 255, 203, 217, 226,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 178, 201, 215, 255, 0, 79,
+ 130, 255, 15, 93, 139, 255, 235, 241, 244, 255, 255, 255, 255, 255, 244,
+ 246, 247, 255, 163, 190, 207, 255, 101, 144, 174, 255, 54, 109, 148, 255,
+ 65, 116, 153, 255, 114, 154, 181, 255, 175, 198, 212, 255, 245, 246, 247,
+ 255, 253, 253, 253, 255, 246, 247, 248, 255, 236, 240, 244, 255, 238, 242,
+ 245, 255, 255, 254, 252, 255, 200, 215, 225, 255, 128, 164, 188, 255, 104,
+ 147, 177, 255, 128, 165, 189, 255, 186, 202, 216, 255, 248, 247, 248, 255,
+ 252, 252, 252, 255, 254, 254, 253, 255, 252, 251, 251, 255, 186, 203, 216,
+ 255, 135, 171, 194, 255, 121, 162, 188, 255, 140, 174, 196, 255, 191, 209,
+ 221, 255, 171, 196, 212, 255, 3, 86, 135, 255, 9, 87, 136, 255, 202,
+ 212, 221, 255, 255, 255, 255, 255, 254, 252, 251, 255, 186, 204, 217, 255,
+ 115, 157, 184, 255, 61, 116, 154, 255, 56, 111, 151, 255, 101, 146, 175,
+ 255, 169, 191, 208, 255, 240, 242, 243, 255, 254, 253, 252, 255, 247, 247,
+ 247, 255, 244, 243, 244, 255, 246, 243, 244, 255, 246, 247, 246, 255, 163,
+ 190, 206, 255, 90, 132, 165, 255, 139, 167, 189, 255, 236, 237, 239, 255,
+ 198, 206, 217, 255, 198, 205, 215, 255, 181, 193, 206, 255, 246, 247, 248,
+ 255, 229, 228, 228, 233, 24, 24, 24, 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, 0, 0, 0, 0, 0, 0, 0, 0, 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, 62, 62, 63, 209, 209, 209, 212, 250, 251,
+ 251, 253, 249, 254, 255, 255, 247, 235, 223, 255, 240, 170, 103, 255, 237,
+ 139, 41, 255, 237, 144, 52, 255, 238, 146, 54, 255, 238, 145, 54, 255,
+ 238, 140, 44, 255, 242, 181, 123, 255, 251, 255, 255, 255, 253, 253, 253,
+ 255, 133, 169, 192, 255, 0, 78, 130, 255, 0, 82, 132, 255, 2, 85,
+ 134, 255, 2, 85, 134, 255, 0, 78, 129, 255, 23, 92, 138, 255, 196,
+ 210, 221, 255, 255, 255, 255, 255, 245, 212, 185, 255, 236, 141, 46, 255,
+ 237, 144, 51, 255, 236, 141, 45, 255, 239, 163, 90, 255, 250, 248, 247,
+ 255, 255, 255, 255, 255, 153, 181, 200, 255, 0, 75, 127, 255, 22, 93,
+ 139, 255, 42, 106, 148, 255, 0, 69, 122, 255, 0, 63, 118, 255, 0,
+ 62, 117, 255, 0, 70, 123, 255, 9, 84, 133, 255, 150, 179, 199, 255,
+ 255, 255, 255, 255, 178, 201, 215, 255, 0, 78, 129, 255, 14, 92, 138,
+ 255, 241, 245, 247, 255, 234, 240, 243, 255, 69, 126, 163, 255, 0, 70,
+ 123, 255, 0, 72, 124, 255, 43, 109, 150, 255, 39, 106, 147, 255, 0,
+ 74, 126, 255, 0, 72, 125, 255, 107, 149, 177, 255, 255, 255, 255, 255,
+ 176, 199, 213, 255, 15, 89, 136, 255, 28, 101, 145, 255, 101, 145, 174,
+ 255, 0, 79, 129, 255, 0, 70, 122, 255, 0, 69, 122, 255, 0, 71,
+ 124, 255, 0, 78, 128, 255, 125, 162, 186, 255, 255, 255, 254, 255, 246,
+ 247, 248, 255, 107, 151, 179, 255, 1, 80, 130, 255, 0, 69, 123, 255,
+ 0, 65, 120, 255, 0, 67, 121, 255, 0, 77, 128, 255, 30, 102, 146,
+ 255, 8, 88, 136, 255, 10, 88, 136, 255, 204, 213, 222, 255, 248, 250,
+ 250, 255, 111, 154, 182, 255, 0, 81, 131, 255, 0, 73, 126, 255, 37,
+ 105, 148, 255, 52, 115, 154, 255, 4, 83, 132, 255, 0, 74, 126, 255,
+ 74, 128, 163, 255, 236, 239, 242, 255, 223, 228, 232, 255, 61, 114, 152,
+ 255, 63, 114, 152, 255, 89, 137, 168, 255, 0, 76, 127, 255, 0, 57,
+ 114, 255, 73, 125, 161, 255, 255, 250, 248, 255, 249, 248, 248, 255, 247,
+ 247, 247, 255, 247, 247, 246, 255, 245, 245, 245, 255, 255, 255, 255, 255,
+ 112, 112, 112, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 2, 2, 2, 107, 107, 107, 108,
+ 246, 246, 246, 249, 255, 255, 255, 255, 247, 252, 255, 255, 243, 215, 190,
+ 255, 237, 151, 69, 255, 236, 139, 43, 255, 236, 144, 53, 255, 236, 145,
+ 53, 255, 237, 145, 53, 255, 237, 144, 52, 255, 236, 143, 53, 255, 245,
+ 217, 197, 255, 255, 255, 255, 255, 206, 218, 227, 255, 8, 87, 135, 255,
+ 0, 83, 132, 255, 5, 86, 135, 255, 5, 86, 135, 255, 5, 86, 135,
+ 255, 5, 86, 134, 255, 0, 76, 127, 255, 73, 128, 162, 255, 251, 252,
+ 253, 255, 250, 241, 234, 255, 237, 151, 69, 255, 236, 141, 48, 255, 236,
+ 142, 49, 255, 236, 145, 57, 255, 247, 230, 219, 255, 255, 255, 255, 255,
+ 153, 180, 200, 255, 0, 76, 127, 255, 0, 79, 129, 255, 8, 87, 134,
+ 255, 100, 146, 176, 255, 144, 174, 196, 255, 123, 163, 188, 255, 36, 104,
+ 147, 255, 0, 75, 126, 255, 10, 82, 130, 255, 202, 214, 223, 255, 186,
+ 206, 219, 255, 0, 78, 128, 255, 15, 93, 138, 255, 243, 245, 246, 255,
+ 113, 152, 179, 255, 0, 68, 120, 255, 7, 82, 131, 255, 154, 181, 201,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 163, 186, 203, 255, 2, 79,
+ 129, 255, 0, 75, 126, 255, 167, 188, 204, 255, 177, 199, 212, 255, 0,
+ 77, 127, 255, 0, 79, 129, 255, 0, 80, 129, 255, 90, 140, 171, 255,
+ 185, 197, 211, 255, 158, 181, 200, 255, 28, 100, 144, 255, 0, 75, 126,
+ 255, 34, 102, 145, 255, 252, 251, 249, 255, 147, 178, 197, 255, 0, 73,
+ 125, 255, 0, 79, 130, 255, 60, 120, 158, 255, 139, 173, 195, 255, 147,
+ 175, 196, 255, 83, 135, 167, 255, 0, 81, 130, 255, 1, 83, 133, 255,
+ 11, 88, 136, 255, 214, 219, 226, 255, 167, 192, 207, 255, 0, 75, 127,
+ 255, 0, 79, 129, 255, 116, 156, 182, 255, 255, 254, 252, 255, 255, 255,
+ 254, 255, 196, 208, 219, 255, 25, 96, 140, 255, 0, 71, 124, 255, 110,
+ 153, 180, 255, 219, 224, 229, 255, 7, 87, 134, 255, 0, 79, 130, 255,
+ 0, 80, 129, 255, 72, 126, 161, 255, 124, 161, 187, 255, 168, 191, 207,
+ 255, 249, 247, 246, 255, 246, 246, 246, 255, 245, 245, 245, 255, 245, 245,
+ 244, 255, 244, 244, 244, 255, 255, 255, 255, 255, 166, 166, 166, 171, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 22,
+ 22, 22, 157, 157, 157, 158, 255, 255, 255, 255, 250, 254, 255, 255, 246,
+ 247, 248, 255, 240, 196, 154, 255, 234, 141, 50, 255, 235, 141, 47, 255,
+ 235, 144, 53, 255, 235, 141, 48, 255, 235, 143, 52, 255, 235, 144, 53,
+ 255, 235, 142, 50, 255, 236, 149, 63, 255, 246, 237, 230, 255, 255, 255,
+ 255, 255, 167, 192, 208, 255, 0, 81, 131, 255, 3, 85, 133, 255, 5,
+ 86, 134, 255, 5, 85, 134, 255, 5, 85, 134, 255, 4, 85, 134, 255,
+ 0, 81, 131, 255, 40, 104, 146, 255, 240, 243, 245, 255, 251, 249, 250,
+ 255, 237, 163, 99, 255, 235, 139, 43, 255, 235, 142, 50, 255, 234, 139,
+ 47, 255, 243, 209, 184, 255, 255, 255, 255, 255, 152, 180, 199, 255, 0,
+ 75, 126, 255, 2, 76, 127, 255, 143, 172, 193, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 191, 207, 218, 255, 4, 83, 131,
+ 255, 0, 70, 122, 255, 107, 150, 178, 255, 186, 205, 217, 255, 0, 79,
+ 128, 255, 20, 95, 141, 255, 207, 218, 226, 255, 15, 90, 136, 255, 0,
+ 76, 127, 255, 33, 101, 144, 255, 170, 193, 208, 255, 172, 195, 210, 255,
+ 173, 197, 211, 255, 157, 185, 203, 255, 8, 88, 135, 255, 0, 75, 126,
+ 255, 40, 105, 146, 255, 155, 181, 200, 255, 1, 83, 131, 255, 0, 74,
+ 125, 255, 92, 140, 172, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 137, 171, 192, 255, 0, 73, 124, 255, 20, 95, 141, 255,
+ 223, 229, 235, 255, 39, 104, 145, 255, 0, 75, 126, 255, 50, 112, 151,
+ 255, 243, 242, 243, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253,
+ 252, 255, 101, 144, 173, 255, 0, 76, 127, 255, 12, 89, 135, 255, 200,
+ 208, 218, 255, 71, 125, 160, 255, 0, 77, 128, 255, 12, 89, 136, 255,
+ 152, 180, 198, 255, 174, 197, 211, 255, 170, 194, 209, 255, 177, 197, 210,
+ 255, 61, 118, 155, 255, 0, 75, 126, 255, 44, 110, 150, 255, 202, 212,
+ 221, 255, 17, 92, 137, 255, 0, 75, 126, 255, 76, 130, 164, 255, 251,
+ 248, 246, 255, 255, 255, 254, 255, 255, 252, 250, 255, 244, 244, 244, 255,
+ 244, 244, 244, 255, 244, 244, 244, 255, 244, 244, 244, 255, 243, 243, 243,
+ 255, 254, 254, 254, 255, 172, 172, 172, 179, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 31, 31, 31, 31, 199, 199, 199, 202, 255, 255, 255,
+ 255, 247, 252, 255, 255, 244, 235, 228, 255, 237, 175, 114, 255, 232, 137,
+ 42, 255, 233, 141, 49, 255, 234, 142, 51, 255, 233, 138, 44, 255, 235,
+ 156, 79, 255, 234, 146, 59, 255, 234, 142, 51, 255, 234, 142, 50, 255,
+ 235, 146, 59, 255, 245, 229, 219, 255, 255, 255, 255, 255, 192, 208, 219,
+ 255, 0, 81, 130, 255, 1, 83, 132, 255, 4, 85, 133, 255, 4, 85,
+ 133, 255, 4, 85, 133, 255, 4, 85, 133, 255, 0, 78, 128, 255, 53,
+ 115, 153, 255, 245, 247, 249, 255, 250, 246, 244, 255, 236, 155, 80, 255,
+ 234, 139, 45, 255, 233, 142, 50, 255, 232, 137, 42, 255, 241, 201, 169,
+ 255, 255, 255, 255, 255, 152, 179, 198, 255, 0, 73, 123, 255, 15, 92,
+ 137, 255, 235, 238, 240, 255, 254, 252, 251, 255, 248, 248, 248, 255, 252,
+ 251, 250, 255, 242, 243, 244, 255, 33, 99, 142, 255, 0, 71, 124, 255,
+ 76, 131, 165, 255, 175, 198, 213, 255, 0, 79, 128, 255, 22, 97, 142,
+ 255, 182, 198, 211, 255, 9, 85, 133, 255, 0, 81, 129, 255, 0, 81,
+ 129, 255, 0, 72, 123, 255, 0, 71, 122, 255, 0, 71, 122, 255, 0,
+ 72, 123, 255, 0, 75, 125, 255, 0, 73, 124, 255, 14, 88, 134, 255,
+ 134, 166, 187, 255, 1, 83, 131, 255, 2, 79, 128, 255, 185, 198, 210,
+ 255, 255, 255, 255, 255, 248, 248, 248, 255, 255, 255, 255, 255, 161, 186,
+ 202, 255, 0, 74, 125, 255, 23, 97, 141, 255, 204, 216, 225, 255, 14,
+ 91, 137, 255, 0, 72, 124, 255, 103, 147, 175, 255, 255, 255, 252, 255,
+ 248, 248, 248, 255, 247, 247, 247, 255, 255, 255, 255, 255, 174, 196, 211,
+ 255, 0, 79, 129, 255, 12, 89, 135, 255, 179, 194, 207, 255, 20, 95,
+ 141, 255, 1, 82, 131, 255, 4, 84, 133, 255, 0, 77, 127, 255, 0,
+ 74, 124, 255, 0, 74, 125, 255, 0, 74, 125, 255, 0, 77, 127, 255,
+ 0, 76, 125, 255, 15, 89, 135, 255, 184, 198, 210, 255, 18, 93, 138,
+ 255, 0, 72, 123, 255, 136, 169, 191, 255, 255, 255, 253, 255, 244, 244,
+ 244, 255, 244, 244, 244, 255, 244, 244, 244, 255, 243, 243, 243, 255, 243,
+ 243, 243, 255, 243, 243, 243, 255, 242, 242, 242, 255, 255, 255, 255, 255,
+ 165, 165, 165, 171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21, 198,
+ 198, 198, 203, 255, 255, 255, 255, 244, 249, 253, 255, 241, 219, 201, 255,
+ 233, 154, 79, 255, 231, 135, 38, 255, 232, 141, 51, 255, 232, 140, 48,
+ 255, 232, 137, 42, 255, 237, 176, 119, 255, 243, 230, 220, 255, 234, 149,
+ 67, 255, 233, 140, 49, 255, 233, 142, 51, 255, 232, 138, 45, 255, 240,
+ 201, 168, 255, 249, 254, 255, 255, 243, 243, 244, 255, 72, 126, 160, 255,
+ 0, 73, 124, 255, 2, 83, 131, 255, 4, 84, 132, 255, 4, 84, 132,
+ 255, 0, 80, 130, 255, 0, 74, 125, 255, 147, 175, 195, 255, 255, 255,
+ 255, 255, 245, 229, 216, 255, 233, 144, 55, 255, 233, 140, 48, 255, 233,
+ 140, 49, 255, 232, 138, 47, 255, 241, 210, 186, 255, 255, 255, 255, 255,
+ 151, 178, 197, 255, 0, 73, 123, 255, 11, 88, 134, 255, 218, 225, 231,
+ 255, 255, 255, 253, 255, 247, 247, 247, 255, 255, 253, 252, 255, 232, 236,
+ 239, 255, 18, 92, 137, 255, 0, 71, 123, 255, 83, 136, 167, 255, 178,
+ 199, 213, 255, 0, 79, 128, 255, 22, 96, 140, 255, 189, 204, 215, 255,
+ 6, 84, 132, 255, 0, 76, 126, 255, 45, 108, 148, 255, 166, 183, 200,
+ 255, 162, 179, 197, 255, 160, 179, 197, 255, 168, 184, 200, 255, 175, 189,
+ 204, 255, 167, 183, 200, 255, 175, 190, 205, 255, 154, 180, 198, 255, 0,
+ 78, 128, 255, 7, 84, 132, 255, 206, 214, 222, 255, 254, 253, 251, 255,
+ 247, 247, 247, 255, 255, 255, 254, 255, 157, 183, 200, 255, 0, 74, 124,
+ 255, 22, 96, 141, 255, 210, 220, 227, 255, 20, 93, 138, 255, 0, 72,
+ 124, 255, 88, 136, 168, 255, 255, 255, 252, 255, 249, 249, 248, 255, 247,
+ 247, 247, 255, 255, 255, 255, 255, 164, 188, 204, 255, 0, 77, 127, 255,
+ 12, 88, 134, 255, 186, 198, 210, 255, 38, 104, 146, 255, 0, 78, 128,
+ 255, 22, 93, 138, 255, 159, 177, 196, 255, 162, 181, 198, 255, 159, 178,
+ 196, 255, 164, 182, 199, 255, 173, 187, 203, 255, 165, 182, 199, 255, 171,
+ 186, 202, 255, 199, 209, 218, 255, 12, 89, 134, 255, 0, 77, 126, 255,
+ 175, 189, 202, 255, 254, 251, 249, 255, 243, 243, 243, 255, 243, 243, 243,
+ 255, 243, 243, 243, 255, 243, 243, 243, 255, 242, 242, 242, 255, 242, 242,
+ 242, 255, 242, 242, 242, 255, 255, 255, 255, 255, 127, 127, 127, 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, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 123, 123, 123, 126, 255, 255, 255, 255, 244, 247,
+ 250, 255, 237, 204, 174, 255, 230, 140, 50, 255, 230, 136, 43, 255, 231,
+ 141, 52, 255, 231, 138, 45, 255, 231, 138, 48, 255, 237, 190, 146, 255,
+ 245, 246, 249, 255, 245, 247, 251, 255, 235, 164, 103, 255, 231, 137, 42,
+ 255, 232, 141, 51, 255, 231, 137, 43, 255, 235, 163, 95, 255, 244, 243,
+ 244, 255, 252, 253, 254, 255, 228, 230, 234, 255, 79, 129, 162, 255, 0,
+ 79, 128, 255, 0, 72, 123, 255, 0, 73, 124, 255, 17, 88, 134, 255,
+ 128, 164, 186, 255, 251, 249, 248, 255, 249, 253, 255, 255, 238, 189, 144,
+ 255, 231, 137, 42, 255, 232, 141, 50, 255, 232, 139, 47, 255, 232, 144,
+ 57, 255, 244, 231, 221, 255, 255, 255, 255, 255, 151, 177, 196, 255, 0,
+ 74, 124, 255, 0, 74, 125, 255, 91, 138, 169, 255, 244, 244, 245, 255,
+ 255, 255, 253, 255, 251, 250, 248, 255, 128, 163, 187, 255, 0, 77, 127,
+ 255, 0, 69, 121, 255, 136, 167, 190, 255, 187, 206, 217, 255, 0, 77,
+ 127, 255, 18, 92, 137, 255, 226, 231, 235, 255, 51, 111, 149, 255, 0,
+ 69, 121, 255, 38, 103, 143, 255, 227, 231, 234, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 206, 217, 225, 255, 145, 173, 193, 255, 229, 234, 237,
+ 255, 255, 255, 255, 255, 169, 192, 207, 255, 0, 76, 126, 255, 7, 85,
+ 132, 255, 210, 217, 224, 255, 253, 251, 250, 255, 246, 246, 246, 255, 255,
+ 255, 253, 255, 157, 182, 200, 255, 0, 74, 124, 255, 17, 93, 138, 255,
+ 238, 239, 241, 255, 89, 135, 165, 255, 0, 72, 123, 255, 19, 90, 135,
+ 255, 180, 197, 211, 255, 255, 251, 249, 255, 255, 254, 251, 255, 220, 226,
+ 231, 255, 52, 112, 150, 255, 0, 77, 126, 255, 10, 86, 132, 255, 209,
+ 214, 221, 255, 121, 157, 182, 255, 0, 70, 122, 255, 12, 86, 133, 255,
+ 188, 202, 214, 255, 255, 255, 255, 255, 255, 255, 255, 255, 227, 232, 235,
+ 255, 142, 173, 194, 255, 222, 227, 231, 255, 255, 255, 254, 255, 210, 218,
+ 224, 255, 10, 86, 132, 255, 0, 77, 125, 255, 175, 189, 202, 255, 254,
+ 250, 248, 255, 242, 242, 242, 255, 242, 242, 242, 255, 242, 242, 242, 255,
+ 242, 242, 242, 255, 242, 242, 242, 255, 241, 241, 241, 255, 246, 246, 246,
+ 255, 231, 231, 231, 241, 39, 39, 39, 38, 0, 0, 0, 0, 0, 0,
+ 0, 0, 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, 10, 10, 9,
+ 215, 215, 215, 222, 249, 253, 255, 255, 239, 219, 201, 255, 229, 139, 51,
+ 255, 229, 137, 45, 255, 229, 140, 50, 255, 229, 135, 41, 255, 230, 143,
+ 57, 255, 238, 204, 173, 255, 244, 249, 253, 255, 245, 246, 248, 255, 244,
+ 250, 255, 255, 237, 194, 154, 255, 230, 135, 40, 255, 231, 141, 50, 255,
+ 231, 140, 50, 255, 231, 136, 44, 255, 237, 185, 141, 255, 245, 248, 253,
+ 255, 251, 252, 254, 255, 251, 248, 246, 255, 175, 193, 207, 255, 113, 152,
+ 179, 255, 128, 162, 186, 255, 210, 217, 224, 255, 255, 253, 252, 255, 248,
+ 254, 255, 255, 240, 211, 185, 255, 230, 139, 49, 255, 231, 139, 47, 255,
+ 231, 140, 50, 255, 230, 136, 42, 255, 233, 158, 87, 255, 245, 244, 243,
+ 255, 255, 255, 255, 255, 148, 175, 194, 255, 0, 69, 121, 255, 0, 78,
+ 127, 255, 0, 74, 124, 255, 41, 104, 144, 255, 109, 149, 176, 255, 65,
+ 120, 156, 255, 0, 75, 124, 255, 0, 69, 121, 255, 36, 100, 141, 255,
+ 239, 240, 241, 255, 177, 199, 212, 255, 0, 71, 123, 255, 6, 86, 132,
+ 255, 241, 244, 244, 255, 190, 203, 214, 255, 13, 83, 129, 255, 0, 68,
+ 119, 255, 24, 94, 138, 255, 119, 160, 185, 255, 107, 151, 178, 255, 4,
+ 82, 129, 255, 0, 57, 112, 255, 70, 120, 155, 255, 254, 253, 252, 255,
+ 166, 190, 205, 255, 0, 70, 122, 255, 0, 80, 128, 255, 207, 215, 222,
+ 255, 253, 251, 250, 255, 246, 246, 246, 255, 255, 255, 253, 255, 154, 180,
+ 198, 255, 0, 68, 120, 255, 8, 87, 134, 255, 240, 243, 243, 255, 192,
+ 207, 217, 255, 4, 80, 128, 255, 0, 73, 124, 255, 3, 82, 129, 255,
+ 82, 130, 162, 255, 101, 143, 171, 255, 21, 90, 135, 255, 0, 72, 123,
+ 255, 0, 78, 127, 255, 1, 80, 128, 255, 204, 212, 219, 255, 222, 228,
+ 233, 255, 36, 101, 143, 255, 0, 70, 121, 255, 11, 85, 131, 255, 104,
+ 147, 174, 255, 119, 158, 183, 255, 35, 100, 141, 255, 0, 62, 116, 255,
+ 34, 98, 140, 255, 232, 233, 235, 255, 211, 218, 224, 255, 2, 81, 129,
+ 255, 0, 72, 121, 255, 172, 186, 200, 255, 253, 250, 248, 255, 242, 242,
+ 242, 255, 241, 241, 241, 255, 241, 241, 241, 255, 241, 241, 241, 255, 240,
+ 240, 240, 255, 241, 241, 241, 255, 255, 255, 255, 255, 140, 140, 140, 145,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 231, 231, 231, 238, 245,
+ 251, 255, 255, 236, 199, 168, 255, 227, 130, 35, 255, 228, 136, 45, 255,
+ 227, 132, 37, 255, 230, 152, 77, 255, 239, 219, 202, 255, 244, 250, 255,
+ 255, 251, 251, 252, 255, 245, 245, 245, 255, 244, 248, 251, 255, 240, 221,
+ 204, 255, 230, 140, 52, 255, 230, 138, 47, 255, 230, 140, 50, 255, 230,
+ 139, 48, 255, 229, 136, 44, 255, 235, 180, 132, 255, 243, 235, 230, 255,
+ 246, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 252, 255, 255, 255, 244, 244, 245, 255, 238, 198, 161, 255, 230, 141,
+ 53, 255, 230, 138, 45, 255, 230, 139, 49, 255, 230, 139, 49, 255, 229,
+ 132, 36, 255, 236, 184, 136, 255, 245, 250, 254, 255, 254, 253, 252, 255,
+ 164, 185, 201, 255, 39, 95, 137, 255, 72, 121, 155, 255, 141, 170, 190,
+ 255, 31, 96, 139, 255, 0, 70, 120, 255, 0, 70, 120, 255, 5, 81,
+ 128, 255, 62, 115, 151, 255, 201, 211, 219, 255, 255, 255, 254, 255, 185,
+ 203, 214, 255, 41, 100, 141, 255, 52, 112, 149, 255, 233, 237, 239, 255,
+ 255, 254, 252, 255, 187, 202, 213, 255, 74, 123, 157, 255, 17, 88, 133,
+ 255, 0, 70, 120, 255, 0, 72, 122, 255, 20, 92, 136, 255, 75, 124,
+ 158, 255, 183, 200, 212, 255, 253, 253, 252, 255, 179, 197, 210, 255, 41,
+ 99, 141, 255, 47, 107, 146, 255, 213, 219, 225, 255, 251, 249, 248, 255,
+ 245, 245, 245, 255, 253, 252, 251, 255, 170, 190, 204, 255, 40, 97, 138,
+ 255, 54, 113, 150, 255, 232, 236, 239, 255, 254, 252, 249, 255, 165, 186,
+ 201, 255, 39, 101, 142, 255, 2, 79, 127, 255, 0, 71, 121, 255, 0,
+ 73, 123, 255, 52, 111, 150, 255, 113, 152, 178, 255, 46, 107, 146, 255,
+ 46, 106, 145, 255, 203, 211, 218, 255, 255, 254, 252, 255, 213, 219, 226,
+ 255, 90, 136, 166, 255, 21, 91, 136, 255, 0, 74, 124, 255, 0, 72,
+ 122, 255, 14, 87, 133, 255, 65, 118, 154, 255, 166, 190, 205, 255, 249,
+ 249, 247, 255, 212, 219, 224, 255, 48, 107, 145, 255, 40, 99, 139, 255,
+ 181, 193, 205, 255, 250, 248, 246, 255, 241, 241, 241, 255, 241, 241, 241,
+ 255, 240, 240, 240, 255, 240, 240, 240, 255, 240, 240, 240, 255, 255, 255,
+ 255, 255, 199, 199, 199, 205, 10, 10, 10, 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, 8, 8, 8, 7, 194, 194, 194, 202, 250, 253, 254, 255, 238, 227,
+ 219, 255, 230, 161, 95, 255, 228, 143, 60, 255, 231, 170, 111, 255, 239,
+ 231, 224, 255, 245, 250, 254, 255, 255, 255, 255, 255, 159, 159, 159, 163,
+ 136, 136, 136, 139, 253, 253, 254, 255, 243, 246, 250, 255, 234, 179, 130,
+ 255, 228, 132, 36, 255, 229, 139, 50, 255, 229, 139, 50, 255, 229, 138,
+ 48, 255, 229, 134, 41, 255, 230, 150, 72, 255, 236, 193, 154, 255, 239,
+ 216, 194, 255, 240, 223, 211, 255, 240, 220, 203, 255, 238, 204, 172, 255,
+ 232, 163, 97, 255, 228, 135, 42, 255, 229, 137, 46, 255, 229, 139, 49,
+ 255, 229, 139, 49, 255, 229, 135, 43, 255, 229, 140, 54, 255, 241, 223,
+ 207, 255, 245, 248, 251, 255, 244, 244, 244, 255, 241, 241, 242, 255, 236,
+ 237, 239, 255, 239, 239, 240, 255, 253, 250, 248, 255, 233, 235, 237, 255,
+ 190, 200, 211, 255, 173, 187, 200, 255, 201, 210, 218, 255, 244, 244, 244,
+ 255, 252, 251, 248, 255, 245, 245, 244, 255, 242, 242, 243, 255, 237, 238,
+ 239, 255, 238, 239, 240, 255, 244, 244, 244, 255, 245, 245, 244, 255, 253,
+ 250, 248, 255, 248, 246, 245, 255, 224, 228, 232, 255, 197, 206, 215, 255,
+ 201, 209, 217, 255, 228, 231, 235, 255, 248, 247, 245, 255, 252, 249, 248,
+ 255, 244, 244, 244, 255, 242, 242, 242, 255, 237, 238, 239, 255, 237, 238,
+ 239, 255, 243, 243, 243, 255, 244, 244, 244, 255, 244, 244, 244, 255, 244,
+ 244, 244, 255, 241, 242, 242, 255, 237, 238, 239, 255, 237, 238, 239, 255,
+ 243, 243, 243, 255, 244, 244, 244, 255, 252, 249, 247, 255, 232, 234, 236,
+ 255, 192, 201, 212, 255, 173, 187, 200, 255, 198, 207, 216, 255, 241, 241,
+ 241, 255, 250, 247, 246, 255, 236, 237, 238, 255, 236, 237, 238, 255, 241,
+ 241, 241, 255, 243, 243, 243, 255, 249, 247, 246, 255, 250, 246, 245, 255,
+ 227, 230, 233, 255, 199, 208, 216, 255, 193, 203, 212, 255, 220, 225, 229,
+ 255, 243, 242, 242, 255, 251, 248, 246, 255, 241, 241, 241, 255, 240, 240,
+ 240, 255, 234, 235, 237, 255, 233, 234, 236, 255, 237, 238, 238, 255, 240,
+ 240, 240, 255, 240, 240, 240, 255, 240, 240, 240, 255, 240, 240, 240, 255,
+ 244, 244, 244, 255, 254, 254, 254, 255, 194, 194, 194, 199, 43, 43, 43,
+ 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 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, 84, 84, 87, 253, 253, 252, 255, 246, 247, 248, 255, 240, 238, 238,
+ 255, 239, 234, 229, 255, 240, 242, 243, 255, 250, 252, 254, 255, 247, 247,
+ 246, 252, 134, 134, 134, 134, 0, 0, 0, 0, 30, 30, 30, 31, 226,
+ 226, 225, 235, 248, 250, 253, 255, 240, 231, 225, 255, 230, 154, 83, 255,
+ 227, 133, 39, 255, 228, 138, 49, 255, 228, 138, 49, 255, 228, 138, 49,
+ 255, 228, 135, 44, 255, 227, 133, 39, 255, 228, 138, 49, 255, 228, 140,
+ 55, 255, 228, 139, 52, 255, 227, 134, 42, 255, 227, 134, 41, 255, 228,
+ 138, 48, 255, 228, 138, 49, 255, 228, 138, 49, 255, 228, 135, 43, 255,
+ 228, 137, 47, 255, 237, 205, 176, 255, 245, 248, 252, 255, 253, 253, 253,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 255, 253, 253,
+ 253, 255, 253, 253, 253, 255, 254, 254, 254, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 253, 255,
+ 252, 252, 252, 255, 252, 252, 252, 255, 252, 252, 252, 255, 255, 254, 253,
+ 255, 255, 254, 253, 255, 252, 252, 252, 255, 251, 251, 251, 255, 251, 251,
+ 251, 255, 252, 252, 252, 255, 254, 254, 254, 255, 225, 225, 225, 232, 141,
+ 141, 141, 145, 8, 8, 8, 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, 0, 0, 0, 0, 0, 1, 1, 1, 0, 124,
+ 124, 124, 127, 236, 236, 236, 242, 255, 255, 255, 255, 254, 255, 255, 255,
+ 254, 255, 255, 255, 215, 215, 215, 219, 98, 98, 98, 99, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 90, 90, 92, 255, 255,
+ 255, 255, 244, 247, 250, 255, 238, 224, 214, 255, 229, 152, 81, 255, 226,
+ 131, 36, 255, 227, 137, 47, 255, 227, 138, 49, 255, 227, 138, 49, 255,
+ 227, 137, 48, 255, 227, 137, 47, 255, 227, 136, 46, 255, 227, 136, 46,
+ 255, 227, 137, 48, 255, 227, 138, 48, 255, 227, 138, 48, 255, 227, 137,
+ 48, 255, 226, 133, 39, 255, 227, 137, 48, 255, 235, 196, 160, 255, 244,
+ 249, 254, 255, 247, 248, 248, 255, 183, 183, 183, 190, 162, 162, 162, 169,
+ 163, 163, 163, 170, 164, 164, 164, 170, 164, 164, 164, 170, 164, 164, 164,
+ 170, 164, 164, 164, 170, 164, 164, 164, 170, 164, 164, 164, 170, 164, 164,
+ 164, 170, 164, 164, 164, 170, 164, 164, 164, 170, 164, 164, 164, 170, 164,
+ 164, 164, 170, 164, 164, 164, 170, 164, 164, 164, 170, 164, 164, 164, 170,
+ 164, 164, 164, 170, 164, 164, 164, 170, 164, 164, 164, 170, 164, 164, 164,
+ 170, 164, 164, 164, 170, 164, 164, 164, 170, 164, 164, 164, 170, 164, 164,
+ 164, 170, 164, 164, 164, 170, 164, 164, 164, 170, 164, 164, 164, 170, 164,
+ 164, 164, 170, 163, 163, 163, 170, 163, 163, 163, 170, 163, 163, 163, 170,
+ 163, 163, 163, 170, 163, 163, 163, 170, 163, 163, 163, 170, 163, 163, 163,
+ 170, 163, 163, 163, 170, 163, 163, 163, 170, 163, 163, 163, 170, 163, 163,
+ 163, 170, 163, 163, 163, 170, 163, 163, 163, 170, 163, 163, 163, 170, 163,
+ 163, 163, 170, 163, 163, 163, 170, 163, 163, 163, 170, 162, 162, 162, 170,
+ 162, 162, 162, 170, 162, 162, 162, 170, 162, 162, 162, 170, 162, 162, 162,
+ 170, 162, 162, 162, 170, 162, 162, 162, 170, 162, 162, 162, 170, 162, 162,
+ 162, 170, 162, 162, 162, 169, 162, 162, 162, 169, 162, 162, 162, 169, 162,
+ 162, 162, 169, 161, 161, 161, 169, 161, 161, 161, 169, 161, 161, 161, 169,
+ 161, 161, 161, 169, 161, 161, 161, 169, 162, 162, 162, 171, 156, 156, 156,
+ 162, 112, 112, 112, 112, 32, 32, 32, 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, 47, 47,
+ 47, 46, 131, 131, 131, 134, 147, 147, 147, 152, 105, 105, 105, 106, 12,
+ 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 2, 2, 2, 144, 144, 144, 147, 254, 254, 254,
+ 255, 243, 246, 250, 255, 238, 228, 221, 255, 230, 168, 111, 255, 225, 134,
+ 45, 255, 225, 131, 37, 255, 226, 135, 43, 255, 226, 136, 46, 255, 226,
+ 137, 48, 255, 226, 137, 48, 255, 226, 137, 48, 255, 226, 137, 47, 255,
+ 226, 135, 45, 255, 225, 133, 40, 255, 225, 130, 36, 255, 228, 152, 76,
+ 255, 237, 209, 184, 255, 244, 248, 253, 255, 255, 255, 255, 255, 167, 167,
+ 167, 172, 5, 5, 5, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 9, 9, 9, 8, 153, 153, 153, 158, 249, 249, 249, 255,
+ 246, 248, 251, 255, 239, 242, 246, 255, 235, 207, 184, 255, 229, 165, 105,
+ 255, 226, 146, 70, 255, 225, 135, 48, 255, 224, 130, 38, 255, 224, 129,
+ 34, 255, 224, 129, 34, 255, 224, 131, 40, 255, 226, 141, 58, 255, 228,
+ 158, 91, 255, 233, 190, 151, 255, 240, 237, 235, 255, 247, 251, 255, 255,
+ 250, 250, 251, 255, 177, 177, 177, 180, 23, 23, 23, 22, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 113, 113, 113, 115, 225, 225, 225, 233, 253,
+ 254, 254, 255, 244, 248, 252, 255, 239, 241, 244, 255, 238, 232, 228, 255,
+ 235, 209, 191, 255, 232, 190, 152, 255, 231, 184, 138, 255, 232, 185, 138,
+ 255, 232, 196, 164, 255, 237, 225, 217, 255, 240, 240, 240, 255, 246, 250,
+ 255, 255, 255, 255, 255, 255, 230, 230, 230, 235, 110, 110, 110, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 40, 40, 40, 40, 149, 149, 149, 153, 220, 220,
+ 220, 229, 251, 252, 252, 255, 252, 254, 255, 255, 249, 253, 255, 255, 246,
+ 252, 255, 255, 245, 251, 255, 255, 246, 252, 255, 255, 248, 254, 255, 255,
+ 253, 255, 255, 255, 250, 251, 252, 255, 217, 218, 218, 226, 153, 153, 153,
+ 157, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 25, 25, 25, 102, 102, 102,
+ 102, 152, 152, 152, 157, 175, 175, 175, 185, 197, 197, 197, 210, 202, 203,
+ 203, 215, 197, 197, 197, 209, 180, 180, 180, 188, 155, 155, 155, 160, 97,
+ 97, 97, 98, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 7, 7, 7, 8, 8, 8, 8, 7, 7, 7,
+ 6, 1, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+
+ *width = 115;
+ *height = 32;
+
+ // only load the requested logo
+ // allocate a new array
+ *data = new unsigned char[14720];
+ // and copy it. Now we are certain that the calling function
+ // can control the memory location
+ for(int i = 0; i < 14720 /* tmp array size */; i++)
+ {
+ (*data)[i] = logo_blender_raw[i];
+ }
+
+}
+
+
+void GetRawBlender3DLogo(unsigned char **data, int *width, int *height)
+{
+ // create an array that will automatically be deleted when)
+ // we're outta this scope
+ static unsigned char logo_blender3d_raw[]= {255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 57, 255, 255,
+ 255, 243, 255, 255, 255, 252, 255, 255, 255, 251, 255, 255, 255, 200, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 57, 255, 255, 255, 243, 255, 255, 255, 252, 255, 255, 255,
+ 251, 255, 255, 255, 200, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 141, 255, 255, 255, 248,
+ 255, 255, 255, 253, 255, 255, 255, 248, 255, 255, 255, 141, 255, 255, 255,
+ 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 17, 255, 255, 255, 159, 255, 255, 255, 231, 255, 255, 255, 247, 255, 255,
+ 255, 247, 255, 255, 255, 234, 255, 255, 255, 176, 255, 255, 255, 36, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 141, 255, 255, 255,
+ 248, 255, 255, 255, 253, 255, 255, 255, 248, 255, 255, 255, 141, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 86, 207, 207, 207, 255, 70, 70, 70, 255, 118, 118, 118, 255, 255,
+ 255, 255, 236, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 86, 207, 207, 207, 255, 70, 70, 70,
+ 255, 118, 118, 118, 255, 255, 255, 255, 236, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 170,
+ 153, 153, 153, 255, 70, 70, 70, 255, 153, 153, 153, 255, 255, 255, 255,
+ 170, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 141, 255, 255, 255, 255, 239, 239, 239, 255, 153, 153, 153, 255, 137, 137,
+ 137, 255, 137, 137, 137, 255, 153, 153, 153, 255, 223, 223, 223, 255, 255,
+ 255, 255, 255, 255, 255, 255, 141, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 170, 153, 153, 153, 255, 70, 70, 70, 255, 153, 153, 153, 255, 255, 255,
+ 255, 170, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
+ 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
+ 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255,
+ 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 86, 255, 255,
+ 255, 172, 255, 255, 255, 172, 255, 255, 255, 86, 255, 255, 255, 86, 255,
+ 255, 255, 144, 255, 255, 255, 144, 255, 255, 255, 57, 255, 255, 255, 86,
+ 255, 255, 255, 144, 255, 255, 255, 207, 255, 255, 255, 207, 255, 255, 255,
+ 172, 255, 255, 255, 86, 255, 255, 255, 86, 255, 255, 255, 144, 255, 255,
+ 255, 144, 255, 255, 255, 57, 255, 255, 255, 86, 255, 255, 255, 144, 255,
+ 255, 255, 207, 255, 255, 255, 207, 255, 255, 255, 172, 255, 255, 255, 86,
+ 255, 255, 255, 86, 255, 255, 255, 144, 255, 255, 255, 144, 255, 255, 255,
+ 57, 255, 255, 255, 86, 255, 255, 255, 144, 255, 255, 255, 144, 255, 255,
+ 255, 57, 255, 255, 255, 144, 187, 187, 187, 255, 0, 0, 0, 253, 70,
+ 70, 70, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255,
+ 255, 255, 255, 251, 255, 255, 255, 207, 255, 255, 255, 163, 187, 187, 187,
+ 255, 0, 0, 0, 253, 70, 70, 70, 255, 255, 255, 255, 251, 255, 255,
+ 255, 0, 255, 255, 255, 141, 255, 255, 255, 235, 255, 255, 255, 254, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 250, 255, 255, 255, 188,
+ 255, 255, 255, 54, 255, 255, 255, 198, 255, 255, 255, 234, 255, 255, 255,
+ 243, 255, 255, 255, 248, 255, 255, 255, 254, 255, 255, 255, 254, 255, 255,
+ 255, 251, 255, 255, 255, 207, 255, 255, 255, 17, 255, 255, 255, 0, 255,
+ 255, 255, 170, 255, 255, 255, 250, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 137, 137, 137, 255, 0, 0, 0, 253, 137, 137, 137,
+ 255, 255, 255, 255, 228, 255, 255, 255, 141, 255, 255, 255, 235, 255, 255,
+ 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 250, 255,
+ 255, 255, 188, 255, 255, 255, 54, 255, 255, 255, 198, 255, 255, 255, 234,
+ 255, 255, 255, 237, 255, 255, 255, 248, 255, 255, 255, 254, 255, 255, 255,
+ 253, 255, 255, 255, 255, 153, 153, 153, 255, 0, 0, 0, 253, 0, 0,
+ 0, 253, 0, 0, 0, 253, 0, 0, 0, 253, 0, 0, 0, 253, 0,
+ 0, 0, 253, 153, 153, 153, 255, 255, 255, 255, 251, 255, 255, 255, 0,
+ 255, 255, 255, 170, 255, 255, 255, 250, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 137, 137, 137, 255, 0, 0, 0, 253, 137, 137,
+ 137, 255, 255, 255, 255, 228, 255, 255, 255, 0, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 86, 255, 255, 255, 215, 255, 255, 255, 240,
+ 255, 255, 255, 231, 255, 255, 255, 159, 255, 255, 255, 17, 255, 255, 255,
+ 0, 255, 255, 255, 57, 255, 255, 255, 206, 255, 255, 255, 237, 255, 255,
+ 255, 231, 255, 255, 255, 159, 255, 255, 255, 35, 255, 255, 255, 105, 255,
+ 255, 255, 142, 255, 255, 255, 208, 255, 255, 255, 229, 255, 255, 255, 237,
+ 255, 255, 255, 215, 255, 255, 255, 205, 255, 255, 255, 228, 255, 255, 255,
+ 234, 255, 255, 255, 198, 255, 255, 255, 36, 255, 255, 255, 0, 255, 255,
+ 255, 227, 187, 187, 187, 255, 187, 187, 187, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 187, 187, 187, 255, 207, 207, 207, 255, 255, 255, 255, 254,
+ 255, 255, 255, 255, 187, 187, 187, 255, 207, 207, 207, 255, 187, 187, 187,
+ 255, 187, 187, 187, 255, 255, 255, 255, 255, 255, 255, 255, 255, 187, 187,
+ 187, 255, 207, 207, 207, 255, 255, 255, 255, 254, 255, 255, 255, 255, 187,
+ 187, 187, 255, 207, 207, 207, 255, 187, 187, 187, 255, 187, 187, 187, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 187, 187, 187, 255, 207, 207, 207,
+ 255, 255, 255, 255, 254, 255, 255, 255, 255, 187, 187, 187, 255, 207, 207,
+ 207, 255, 255, 255, 255, 170, 255, 255, 255, 172, 187, 187, 187, 255, 0,
+ 0, 0, 253, 70, 70, 70, 255, 153, 153, 153, 255, 86, 86, 86, 255,
+ 70, 70, 70, 255, 118, 118, 118, 255, 239, 239, 239, 255, 255, 255, 255,
+ 255, 187, 187, 187, 255, 0, 0, 0, 253, 70, 70, 70, 255, 255, 255,
+ 255, 254, 255, 255, 255, 246, 255, 255, 255, 255, 153, 153, 153, 255, 118,
+ 118, 118, 255, 69, 69, 69, 254, 70, 70, 70, 255, 137, 137, 137, 255,
+ 239, 239, 239, 255, 255, 255, 255, 254, 223, 223, 223, 255, 137, 137, 137,
+ 255, 153, 153, 153, 255, 169, 169, 169, 255, 102, 102, 102, 255, 70, 70,
+ 70, 255, 118, 118, 118, 255, 239, 239, 239, 255, 255, 255, 255, 236, 255,
+ 255, 255, 236, 255, 255, 255, 255, 137, 137, 137, 255, 70, 70, 70, 255,
+ 70, 70, 70, 255, 137, 137, 137, 255, 118, 118, 118, 255, 0, 0, 0,
+ 253, 137, 137, 137, 255, 255, 255, 255, 254, 255, 255, 255, 255, 153, 153,
+ 153, 255, 118, 118, 118, 255, 69, 69, 69, 254, 70, 70, 70, 255, 137,
+ 137, 137, 255, 239, 239, 239, 255, 255, 255, 255, 254, 223, 223, 223, 255,
+ 137, 137, 137, 255, 153, 153, 153, 255, 207, 207, 207, 255, 86, 86, 86,
+ 255, 70, 70, 70, 255, 223, 223, 223, 255, 0, 0, 0, 253, 0, 0,
+ 0, 253, 137, 137, 137, 255, 255, 255, 255, 255, 239, 239, 239, 255, 86,
+ 86, 86, 255, 0, 0, 0, 253, 34, 34, 34, 255, 255, 255, 255, 253,
+ 255, 255, 255, 236, 255, 255, 255, 255, 137, 137, 137, 255, 70, 70, 70,
+ 255, 70, 70, 70, 255, 137, 137, 137, 255, 118, 118, 118, 255, 0, 0,
+ 0, 253, 137, 137, 137, 255, 255, 255, 255, 233, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 214, 255, 255, 255, 255, 187, 187, 187, 255,
+ 137, 137, 137, 255, 153, 153, 153, 255, 239, 239, 239, 255, 255, 255, 255,
+ 254, 255, 255, 255, 224, 255, 255, 255, 255, 207, 207, 207, 255, 137, 137,
+ 137, 255, 153, 153, 153, 255, 239, 239, 239, 255, 255, 255, 255, 255, 239,
+ 239, 239, 255, 187, 187, 187, 255, 223, 223, 223, 255, 169, 169, 169, 255,
+ 137, 137, 137, 255, 187, 187, 187, 255, 255, 255, 255, 255, 153, 153, 153,
+ 255, 137, 137, 137, 255, 223, 223, 223, 255, 255, 255, 255, 255, 255, 255,
+ 255, 36, 255, 255, 255, 205, 86, 86, 86, 255, 0, 0, 0, 253, 239,
+ 239, 239, 255, 222, 222, 222, 255, 0, 0, 0, 253, 18, 18, 18, 255,
+ 255, 255, 255, 255, 207, 207, 207, 255, 0, 0, 0, 253, 137, 137, 137,
+ 255, 86, 86, 86, 255, 0, 0, 0, 253, 239, 239, 239, 255, 222, 222,
+ 222, 255, 0, 0, 0, 253, 18, 18, 18, 255, 255, 255, 255, 255, 207,
+ 207, 207, 255, 0, 0, 0, 253, 137, 137, 137, 255, 86, 86, 86, 255,
+ 0, 0, 0, 253, 239, 239, 239, 255, 222, 222, 222, 255, 0, 0, 0,
+ 253, 18, 18, 18, 255, 255, 255, 255, 255, 207, 207, 207, 255, 0, 0,
+ 0, 253, 137, 137, 137, 255, 255, 255, 255, 116, 255, 255, 255, 172, 187,
+ 187, 187, 255, 0, 0, 0, 253, 0, 0, 0, 253, 0, 0, 0, 253,
+ 70, 70, 70, 254, 33, 33, 33, 255, 0, 0, 0, 253, 18, 18, 18,
+ 255, 239, 239, 239, 255, 187, 187, 187, 255, 0, 0, 0, 253, 70, 70,
+ 70, 255, 255, 255, 255, 254, 255, 255, 255, 255, 50, 50, 50, 255, 0,
+ 0, 0, 253, 69, 69, 69, 254, 137, 137, 137, 254, 103, 103, 103, 254,
+ 0, 0, 0, 253, 18, 18, 18, 255, 239, 239, 239, 255, 187, 187, 187,
+ 255, 0, 0, 0, 253, 0, 0, 0, 253, 18, 18, 18, 255, 69, 69,
+ 69, 254, 18, 18, 18, 255, 0, 0, 0, 253, 70, 70, 70, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 70, 70, 70, 255, 0, 0, 0, 253,
+ 18, 18, 18, 255, 69, 69, 69, 254, 18, 18, 18, 255, 0, 0, 0,
+ 253, 0, 0, 0, 253, 137, 137, 137, 255, 255, 255, 255, 255, 50, 50,
+ 50, 255, 0, 0, 0, 253, 69, 69, 69, 254, 137, 137, 137, 254, 103,
+ 103, 103, 254, 0, 0, 0, 253, 18, 18, 18, 255, 239, 239, 239, 255,
+ 187, 187, 187, 255, 0, 0, 0, 253, 34, 34, 34, 255, 18, 18, 18,
+ 255, 0, 0, 0, 253, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 86, 86, 86, 255, 0, 0, 0, 253, 34, 34, 34, 255,
+ 255, 255, 255, 253, 255, 255, 255, 255, 70, 70, 70, 255, 0, 0, 0,
+ 253, 18, 18, 18, 255, 69, 69, 69, 254, 18, 18, 18, 255, 0, 0,
+ 0, 253, 0, 0, 0, 253, 137, 137, 137, 255, 255, 255, 255, 233, 255,
+ 255, 255, 0, 255, 255, 255, 57, 255, 255, 255, 255, 102, 102, 102, 255,
+ 0, 0, 0, 253, 49, 49, 49, 253, 18, 18, 18, 255, 18, 18, 18,
+ 255, 223, 223, 223, 255, 255, 255, 255, 255, 102, 102, 102, 255, 0, 0,
+ 0, 253, 49, 49, 49, 253, 18, 18, 18, 255, 18, 18, 18, 255, 207,
+ 207, 207, 255, 187, 187, 187, 255, 0, 0, 0, 253, 18, 18, 18, 255,
+ 50, 50, 50, 254, 18, 18, 18, 255, 0, 0, 0, 253, 34, 34, 34,
+ 255, 70, 70, 70, 253, 18, 18, 18, 255, 0, 0, 0, 253, 223, 223,
+ 223, 255, 255, 255, 255, 170, 255, 255, 255, 230, 153, 153, 153, 255, 0,
+ 0, 0, 253, 169, 169, 169, 255, 153, 153, 153, 255, 18, 18, 18, 255,
+ 0, 0, 0, 253, 207, 207, 207, 255, 137, 137, 137, 255, 0, 0, 0,
+ 253, 207, 207, 207, 255, 153, 153, 153, 255, 0, 0, 0, 253, 169, 169,
+ 169, 255, 153, 153, 153, 255, 18, 18, 18, 255, 0, 0, 0, 253, 207,
+ 207, 207, 255, 137, 137, 137, 255, 0, 0, 0, 253, 207, 207, 207, 255,
+ 153, 153, 153, 255, 0, 0, 0, 253, 169, 169, 169, 255, 153, 153, 153,
+ 255, 18, 18, 18, 255, 0, 0, 0, 253, 207, 207, 207, 255, 137, 137,
+ 137, 255, 0, 0, 0, 253, 207, 207, 207, 255, 255, 255, 255, 170, 255,
+ 255, 255, 172, 187, 187, 187, 255, 0, 0, 0, 253, 18, 18, 18, 255,
+ 207, 207, 207, 255, 255, 255, 255, 255, 255, 255, 255, 255, 86, 86, 86,
+ 255, 0, 0, 0, 253, 137, 137, 137, 255, 187, 187, 187, 255, 0, 0,
+ 0, 253, 70, 70, 70, 255, 255, 255, 255, 255, 169, 169, 169, 255, 0,
+ 0, 0, 253, 86, 86, 86, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 137, 137, 137, 255, 0, 0, 0, 253, 137, 137, 137,
+ 255, 187, 187, 187, 255, 0, 0, 0, 253, 0, 0, 0, 253, 207, 207,
+ 207, 255, 255, 255, 255, 255, 223, 223, 223, 255, 0, 0, 0, 253, 0,
+ 0, 0, 253, 255, 255, 255, 255, 187, 187, 187, 255, 0, 0, 0, 253,
+ 34, 34, 34, 255, 239, 239, 239, 255, 255, 255, 255, 255, 239, 239, 239,
+ 255, 50, 50, 50, 255, 0, 0, 0, 253, 137, 137, 137, 255, 169, 169,
+ 169, 255, 0, 0, 0, 253, 86, 86, 86, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 137, 137, 137, 255, 0, 0, 0, 253,
+ 137, 137, 137, 255, 187, 187, 187, 255, 0, 0, 0, 253, 0, 0, 0,
+ 253, 137, 137, 137, 255, 255, 255, 255, 255, 169, 169, 169, 255, 255, 255,
+ 255, 255, 255, 255, 255, 0, 255, 255, 255, 86, 138, 138, 138, 236, 0,
+ 0, 0, 253, 0, 0, 0, 253, 0, 0, 0, 253, 18, 18, 18, 255,
+ 223, 223, 223, 255, 255, 255, 255, 255, 187, 187, 187, 255, 0, 0, 0,
+ 253, 34, 34, 34, 255, 239, 239, 239, 255, 255, 255, 255, 255, 239, 239,
+ 239, 255, 50, 50, 50, 255, 0, 0, 0, 253, 137, 137, 137, 255, 255,
+ 255, 255, 233, 255, 255, 255, 0, 255, 255, 255, 170, 207, 207, 207, 255,
+ 0, 0, 0, 253, 118, 118, 118, 255, 255, 255, 255, 255, 187, 187, 187,
+ 255, 0, 0, 0, 253, 137, 137, 137, 254, 207, 207, 207, 255, 0, 0,
+ 0, 253, 118, 118, 118, 255, 255, 255, 255, 255, 239, 239, 239, 255, 0,
+ 0, 0, 253, 86, 86, 86, 255, 187, 187, 187, 255, 0, 0, 0, 253,
+ 86, 86, 86, 255, 255, 255, 255, 255, 169, 169, 169, 255, 0, 0, 0,
+ 253, 102, 102, 102, 255, 255, 255, 255, 255, 169, 169, 169, 255, 0, 0,
+ 0, 253, 137, 137, 137, 255, 255, 255, 255, 198, 255, 255, 255, 141, 239,
+ 239, 239, 255, 0, 0, 0, 253, 102, 102, 102, 255, 102, 102, 102, 255,
+ 86, 86, 86, 255, 18, 18, 18, 255, 137, 137, 137, 255, 86, 86, 86,
+ 255, 34, 34, 34, 255, 255, 255, 255, 255, 239, 239, 239, 255, 0, 0,
+ 0, 253, 102, 102, 102, 255, 102, 102, 102, 255, 86, 86, 86, 255, 18,
+ 18, 18, 255, 137, 137, 137, 255, 86, 86, 86, 255, 34, 34, 34, 255,
+ 255, 255, 255, 255, 239, 239, 239, 255, 0, 0, 0, 253, 102, 102, 102,
+ 255, 102, 102, 102, 255, 86, 86, 86, 255, 18, 18, 18, 255, 137, 137,
+ 137, 255, 86, 86, 86, 255, 34, 34, 34, 255, 255, 255, 255, 255, 255,
+ 255, 255, 57, 255, 255, 255, 172, 187, 187, 187, 255, 0, 0, 0, 253,
+ 70, 70, 70, 255, 255, 255, 255, 255, 255, 255, 255, 57, 255, 255, 255,
+ 245, 187, 187, 187, 255, 0, 0, 0, 253, 70, 70, 70, 255, 187, 187,
+ 187, 255, 0, 0, 0, 253, 70, 70, 70, 255, 255, 255, 255, 255, 137,
+ 137, 137, 255, 0, 0, 0, 253, 0, 0, 0, 253, 0, 0, 0, 253,
+ 0, 0, 0, 253, 0, 0, 0, 253, 0, 0, 0, 253, 0, 0, 0,
+ 253, 70, 70, 70, 255, 187, 187, 187, 255, 0, 0, 0, 253, 70, 70,
+ 70, 255, 255, 255, 255, 255, 255, 255, 255, 95, 255, 255, 255, 255, 0,
+ 0, 0, 253, 0, 0, 0, 253, 255, 255, 255, 255, 137, 137, 137, 255,
+ 0, 0, 0, 253, 137, 137, 137, 255, 255, 255, 255, 254, 255, 255, 255,
+ 35, 255, 255, 255, 253, 137, 137, 137, 255, 0, 0, 0, 253, 137, 137,
+ 137, 255, 137, 137, 137, 255, 0, 0, 0, 253, 0, 0, 0, 253, 0,
+ 0, 0, 253, 0, 0, 0, 253, 0, 0, 0, 253, 0, 0, 0, 253,
+ 0, 0, 0, 253, 70, 70, 70, 255, 187, 187, 187, 255, 0, 0, 0,
+ 253, 50, 50, 50, 255, 255, 255, 255, 255, 255, 255, 255, 222, 255, 255,
+ 255, 213, 255, 255, 255, 252, 255, 255, 255, 254, 255, 255, 255, 254, 187,
+ 187, 187, 255, 137, 137, 137, 255, 137, 137, 137, 255, 34, 34, 34, 255,
+ 0, 0, 0, 253, 34, 34, 34, 255, 255, 255, 255, 255, 137, 137, 137,
+ 255, 0, 0, 0, 253, 137, 137, 137, 255, 255, 255, 255, 254, 255, 255,
+ 255, 35, 255, 255, 255, 253, 137, 137, 137, 255, 0, 0, 0, 253, 137,
+ 137, 137, 255, 255, 255, 255, 233, 255, 255, 255, 0, 255, 255, 255, 194,
+ 137, 137, 137, 255, 0, 0, 0, 253, 187, 187, 187, 255, 255, 255, 255,
+ 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 137, 137,
+ 137, 255, 0, 0, 0, 253, 187, 187, 187, 255, 255, 255, 255, 234, 255,
+ 255, 255, 255, 70, 70, 70, 255, 18, 18, 18, 255, 187, 187, 187, 255,
+ 0, 0, 0, 253, 137, 137, 137, 255, 255, 255, 255, 253, 187, 187, 187,
+ 255, 0, 0, 0, 253, 137, 137, 137, 255, 255, 255, 255, 252, 187, 187,
+ 187, 255, 0, 0, 0, 253, 137, 137, 137, 255, 255, 255, 255, 233, 255,
+ 255, 255, 17, 255, 255, 255, 255, 70, 70, 70, 255, 34, 34, 34, 255,
+ 50, 50, 50, 255, 137, 137, 137, 255, 86, 86, 86, 255, 70, 70, 70,
+ 255, 0, 0, 0, 253, 118, 118, 118, 255, 255, 255, 255, 253, 255, 255,
+ 255, 255, 70, 70, 70, 255, 34, 34, 34, 255, 50, 50, 50, 255, 137,
+ 137, 137, 255, 86, 86, 86, 255, 70, 70, 70, 255, 0, 0, 0, 253,
+ 118, 118, 118, 255, 255, 255, 255, 253, 255, 255, 255, 255, 70, 70, 70,
+ 255, 34, 34, 34, 255, 50, 50, 50, 255, 137, 137, 137, 255, 86, 86,
+ 86, 255, 70, 70, 70, 255, 0, 0, 0, 253, 118, 118, 118, 255, 255,
+ 255, 255, 255, 255, 255, 255, 252, 255, 255, 255, 254, 187, 187, 187, 255,
+ 0, 0, 0, 253, 50, 50, 50, 255, 255, 255, 255, 255, 255, 255, 255,
+ 250, 255, 255, 255, 255, 153, 153, 153, 255, 0, 0, 0, 253, 86, 86,
+ 86, 255, 187, 187, 187, 255, 0, 0, 0, 253, 70, 70, 70, 255, 255,
+ 255, 255, 255, 137, 137, 137, 255, 0, 0, 0, 253, 86, 86, 86, 255,
+ 187, 187, 187, 255, 187, 187, 187, 255, 187, 187, 187, 255, 187, 187, 187,
+ 255, 187, 187, 187, 255, 207, 207, 207, 255, 187, 187, 187, 255, 0, 0,
+ 0, 253, 70, 70, 70, 255, 255, 255, 255, 254, 255, 255, 255, 0, 255,
+ 255, 255, 255, 0, 0, 0, 253, 0, 0, 0, 253, 255, 255, 255, 255,
+ 137, 137, 137, 255, 0, 0, 0, 253, 102, 102, 102, 255, 255, 255, 255,
+ 255, 255, 255, 255, 243, 255, 255, 255, 255, 118, 118, 118, 255, 0, 0,
+ 0, 253, 137, 137, 137, 255, 137, 137, 137, 255, 0, 0, 0, 253, 86,
+ 86, 86, 255, 187, 187, 187, 255, 187, 187, 187, 255, 187, 187, 187, 255,
+ 187, 187, 187, 255, 187, 187, 187, 255, 207, 207, 207, 255, 187, 187, 187,
+ 255, 0, 0, 0, 253, 70, 70, 70, 255, 255, 255, 255, 254, 255, 255,
+ 255, 0, 255, 255, 255, 86, 153, 153, 153, 255, 70, 70, 70, 255, 102,
+ 102, 102, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255,
+ 187, 187, 187, 255, 0, 0, 0, 253, 0, 0, 0, 253, 187, 187, 187,
+ 255, 137, 137, 137, 255, 0, 0, 0, 253, 102, 102, 102, 255, 255, 255,
+ 255, 255, 255, 255, 255, 243, 255, 255, 255, 255, 118, 118, 118, 255, 0,
+ 0, 0, 253, 137, 137, 137, 255, 255, 255, 255, 254, 255, 255, 255, 252,
+ 255, 255, 255, 254, 153, 153, 153, 255, 0, 0, 0, 253, 169, 169, 169,
+ 255, 255, 255, 255, 251, 255, 255, 255, 255, 187, 187, 187, 255, 207, 207,
+ 207, 255, 153, 153, 153, 255, 0, 0, 0, 253, 169, 169, 169, 255, 255,
+ 255, 255, 248, 255, 255, 255, 255, 50, 50, 50, 255, 34, 34, 34, 255,
+ 187, 187, 187, 255, 0, 0, 0, 253, 137, 137, 137, 255, 255, 255, 255,
+ 249, 187, 187, 187, 255, 0, 0, 0, 253, 137, 137, 137, 255, 255, 255,
+ 255, 249, 187, 187, 187, 255, 0, 0, 0, 253, 137, 137, 137, 255, 255,
+ 255, 255, 233, 255, 255, 255, 0, 255, 255, 255, 241, 137, 137, 137, 255,
+ 0, 0, 0, 253, 0, 0, 0, 253, 207, 207, 207, 255, 153, 153, 153,
+ 255, 0, 0, 0, 253, 0, 0, 0, 253, 207, 207, 207, 255, 255, 255,
+ 255, 200, 255, 255, 255, 241, 137, 137, 137, 255, 0, 0, 0, 253, 0,
+ 0, 0, 253, 207, 207, 207, 255, 153, 153, 153, 255, 0, 0, 0, 253,
+ 0, 0, 0, 253, 207, 207, 207, 255, 255, 255, 255, 200, 255, 255, 255,
+ 241, 137, 137, 137, 255, 0, 0, 0, 253, 0, 0, 0, 253, 207, 207,
+ 207, 255, 153, 153, 153, 255, 0, 0, 0, 253, 0, 0, 0, 253, 207,
+ 207, 207, 255, 207, 207, 207, 255, 70, 70, 70, 255, 118, 118, 118, 255,
+ 187, 187, 187, 255, 0, 0, 0, 253, 0, 0, 0, 253, 86, 86, 86,
+ 255, 187, 187, 187, 255, 153, 153, 153, 255, 18, 18, 18, 255, 0, 0,
+ 0, 253, 169, 169, 169, 255, 187, 187, 187, 255, 0, 0, 0, 253, 70,
+ 70, 70, 255, 255, 255, 255, 255, 223, 223, 223, 255, 0, 0, 0, 253,
+ 18, 18, 18, 255, 169, 169, 169, 255, 255, 255, 255, 255, 223, 223, 223,
+ 255, 50, 50, 50, 255, 0, 0, 0, 253, 138, 138, 138, 248, 187, 187,
+ 187, 255, 0, 0, 0, 253, 70, 70, 70, 255, 255, 255, 255, 254, 255,
+ 255, 255, 0, 255, 255, 255, 255, 0, 0, 0, 253, 0, 0, 0, 253,
+ 255, 255, 255, 255, 223, 223, 223, 255, 18, 18, 18, 255, 0, 0, 0,
+ 253, 137, 137, 137, 255, 187, 187, 187, 255, 137, 137, 137, 255, 0, 0,
+ 0, 253, 0, 0, 0, 253, 137, 137, 137, 255, 223, 223, 223, 255, 0,
+ 0, 0, 253, 18, 18, 18, 255, 169, 169, 169, 255, 255, 255, 255, 255,
+ 223, 223, 223, 255, 50, 50, 50, 255, 0, 0, 0, 253, 138, 138, 138,
+ 248, 187, 187, 187, 255, 0, 0, 0, 253, 70, 70, 70, 255, 255, 255,
+ 255, 254, 255, 255, 255, 0, 255, 255, 255, 141, 186, 186, 186, 252, 0,
+ 0, 0, 253, 0, 0, 0, 253, 118, 118, 118, 255, 187, 187, 187, 255,
+ 169, 169, 169, 255, 50, 50, 50, 255, 0, 0, 0, 253, 18, 18, 18,
+ 255, 255, 255, 255, 255, 223, 223, 223, 255, 18, 18, 18, 255, 0, 0,
+ 0, 253, 137, 137, 137, 255, 187, 187, 187, 255, 137, 137, 137, 255, 0,
+ 0, 0, 253, 0, 0, 0, 253, 137, 137, 137, 255, 207, 207, 207, 255,
+ 70, 70, 70, 255, 118, 118, 118, 255, 223, 223, 223, 255, 0, 0, 0,
+ 253, 86, 86, 86, 255, 239, 239, 239, 255, 137, 137, 137, 255, 0, 0,
+ 0, 253, 153, 153, 153, 249, 223, 223, 223, 255, 0, 0, 0, 253, 86,
+ 86, 86, 255, 239, 239, 239, 255, 187, 187, 187, 255, 0, 0, 0, 253,
+ 102, 102, 102, 255, 187, 187, 187, 255, 0, 0, 0, 253, 137, 137, 137,
+ 255, 255, 255, 255, 249, 187, 187, 187, 255, 0, 0, 0, 253, 137, 137,
+ 137, 255, 255, 255, 255, 249, 187, 187, 187, 255, 0, 0, 0, 253, 137,
+ 137, 137, 255, 255, 255, 255, 233, 255, 255, 255, 0, 255, 255, 255, 170,
+ 223, 223, 223, 255, 0, 0, 0, 253, 18, 18, 18, 255, 255, 255, 255,
+ 255, 223, 223, 223, 255, 0, 0, 0, 253, 34, 34, 34, 255, 255, 255,
+ 255, 255, 255, 255, 255, 57, 255, 255, 255, 170, 223, 223, 223, 255, 0,
+ 0, 0, 253, 18, 18, 18, 255, 255, 255, 255, 255, 223, 223, 223, 255,
+ 0, 0, 0, 253, 34, 34, 34, 255, 255, 255, 255, 255, 255, 255, 255,
+ 57, 255, 255, 255, 170, 223, 223, 223, 255, 0, 0, 0, 253, 18, 18,
+ 18, 255, 255, 255, 255, 255, 223, 223, 223, 255, 0, 0, 0, 253, 34,
+ 34, 34, 255, 255, 255, 255, 255, 187, 187, 187, 247, 0, 0, 0, 253,
+ 70, 70, 70, 253, 187, 187, 187, 255, 0, 0, 0, 253, 34, 34, 34,
+ 255, 50, 50, 50, 255, 0, 0, 0, 253, 0, 0, 0, 253, 0, 0,
+ 0, 253, 137, 137, 137, 255, 255, 255, 255, 255, 187, 187, 187, 255, 0,
+ 0, 0, 253, 70, 70, 70, 255, 255, 255, 255, 241, 255, 255, 255, 255,
+ 169, 169, 169, 255, 34, 34, 34, 255, 0, 0, 0, 253, 0, 0, 0,
+ 253, 0, 0, 0, 253, 18, 18, 18, 255, 137, 137, 137, 255, 255, 255,
+ 255, 255, 187, 187, 187, 255, 0, 0, 0, 253, 70, 70, 70, 255, 255,
+ 255, 255, 236, 255, 255, 255, 0, 255, 255, 255, 255, 0, 0, 0, 253,
+ 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 254, 153, 153, 153,
+ 255, 18, 18, 18, 255, 0, 0, 0, 253, 0, 0, 0, 253, 18, 18,
+ 18, 255, 70, 70, 70, 255, 0, 0, 0, 253, 137, 137, 137, 255, 255,
+ 255, 255, 255, 169, 169, 169, 255, 34, 34, 34, 255, 0, 0, 0, 253,
+ 0, 0, 0, 253, 0, 0, 0, 253, 18, 18, 18, 255, 137, 137, 137,
+ 255, 255, 255, 255, 255, 187, 187, 187, 255, 0, 0, 0, 253, 70, 70,
+ 70, 255, 255, 255, 255, 236, 255, 255, 255, 0, 255, 255, 255, 86, 255,
+ 255, 255, 255, 153, 153, 153, 255, 34, 34, 34, 255, 0, 0, 0, 253,
+ 0, 0, 0, 253, 0, 0, 0, 253, 0, 0, 0, 253, 50, 50, 50,
+ 255, 187, 187, 187, 255, 255, 255, 255, 254, 255, 255, 255, 254, 153, 153,
+ 153, 255, 18, 18, 18, 255, 0, 0, 0, 253, 0, 0, 0, 253, 18,
+ 18, 18, 255, 70, 70, 70, 255, 0, 0, 0, 253, 137, 137, 137, 255,
+ 187, 187, 187, 251, 0, 0, 0, 253, 70, 70, 70, 252, 255, 255, 255,
+ 255, 153, 153, 153, 255, 18, 18, 18, 255, 0, 0, 0, 253, 0, 0,
+ 0, 253, 102, 102, 102, 255, 255, 255, 255, 255, 255, 255, 255, 255, 153,
+ 153, 153, 255, 18, 18, 18, 255, 0, 0, 0, 253, 0, 0, 0, 253,
+ 70, 70, 70, 255, 239, 239, 239, 255, 187, 187, 187, 255, 0, 0, 0,
+ 253, 137, 137, 137, 255, 255, 255, 255, 215, 187, 187, 187, 255, 0, 0,
+ 0, 253, 137, 137, 137, 255, 255, 255, 255, 215, 187, 187, 187, 255, 0,
+ 0, 0, 253, 137, 137, 137, 255, 255, 255, 255, 170, 255, 255, 255, 0,
+ 255, 255, 255, 36, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 251, 255, 255, 255, 0, 255, 255, 255, 36, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 251, 255, 255, 255, 0, 255, 255, 255, 36, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 215, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 236,
+ 255, 255, 255, 113, 255, 255, 255, 253, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 215, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 236, 255, 255, 255, 0, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 141, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 222, 255, 255, 255, 253, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 215, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 236, 255, 255, 255, 0, 255,
+ 255, 255, 0, 255, 255, 255, 141, 255, 255, 255, 253, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 250, 255, 255, 255, 86, 255, 255,
+ 255, 141, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 214, 255,
+ 255, 255, 141, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 246, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 215, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 215, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 170, };
+
+ *width = 136;
+ *height = 11;
+
+ // only load the requested logo
+ // allocate a new array
+ *data = new unsigned char[5984];
+ // and copy it. Now we are certain that the calling function
+ // can control the memory location
+ for(int i = 0; i < 5984 /* tmp array size */; i++)
+ {
+ (*data)[i] = logo_blender3d_raw[i];
+ }
+
+}
+
+
+
diff --git a/source/gameengine/GamePlayer/common/GPC_RawLogoArrays.h b/source/gameengine/GamePlayer/common/GPC_RawLogoArrays.h
new file mode 100644
index 00000000000..b6caf3a875a
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_RawLogoArrays.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef __GPC_RAWLOGOARRAYS_H
+#define __GPC_RAWLOGOARRAYS_H
+
+void GetRawBlenderLogo(unsigned char **data, int *width, int *height);
+void GetRawBlender3DLogo(unsigned char **data, int *width, int *height);
+#if 0
+void GetRawNaNLogo(unsigned char **data, int *width, int *height);
+#endif
+
+#endif // __GPC_RAWLOGOARRAYS_H
+
diff --git a/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp b/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp
new file mode 100644
index 00000000000..cc5c392d51a
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp
@@ -0,0 +1,596 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 <assert.h>
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#include <windows.h>
+#endif
+
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#else
+#include <GL/gl.h>
+#endif
+#include <iostream>
+
+#include "GPC_RenderTools.h"
+
+#include "RAS_IRenderTools.h"
+#include "RAS_IRasterizer.h"
+#include "RAS_LightObject.h"
+#include "RAS_ICanvas.h"
+#include "RAS_GLExtensionManager.h"
+
+// next two includes/dependencies come from the shadow feature
+// it needs the gameobject and the sumo physics scene for a raycast
+#include "KX_GameObject.h"
+
+#include "GPC_PolygonMaterial.h"
+#include "KX_PolygonMaterial.h"
+#include "Value.h"
+
+//#include "KX_BlenderGL.h" // for text printing
+//#include "KX_BlenderClientObject.h"
+#include "STR_String.h"
+#include "RAS_BucketManager.h" // for polymaterial (needed for textprinting)
+
+
+// Blender includes
+/* This list includes only data type definitions */
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_group_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_property_types.h"
+#include "DNA_text_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_actuator_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_bmfont.h"
+#include "BKE_bmfont_types.h"
+#include "BKE_main.h"
+
+#include "IMB_imbuf_types.h"
+// End of Blender includes
+
+#include "KX_Scene.h"
+#include "KX_RayCast.h"
+#include "KX_IPhysicsController.h"
+#include "PHY_IPhysicsEnvironment.h"
+#include "KX_BlenderMaterial.h"
+
+GPC_RenderTools::GPC_RenderTools()
+{
+ m_font = BMF_GetFont(BMF_kHelvetica10);
+ glGetIntegerv(GL_MAX_LIGHTS, (GLint*) &m_numgllights);
+ if (m_numgllights < 8)
+ m_numgllights = 8;
+}
+
+
+GPC_RenderTools::~GPC_RenderTools()
+{
+}
+
+
+void GPC_RenderTools::EndFrame(RAS_IRasterizer* rasty)
+{
+}
+
+
+void GPC_RenderTools::BeginFrame(RAS_IRasterizer* rasty)
+{
+ m_clientobject=NULL;
+ m_modified=true;
+ DisableOpenGLLights();
+
+}
+
+int GPC_RenderTools::ProcessLighting(int layer)
+{
+ int result = false;
+
+ if (layer < 0)
+ {
+ DisableOpenGLLights();
+ result = false;
+ } else
+ {
+ if (m_clientobject)
+ {
+ if (applyLights(layer))
+ {
+ EnableOpenGLLights();
+ result = true;
+ } else
+ {
+ DisableOpenGLLights();
+ result = false;
+ }
+ }
+ }
+ return result;
+}
+
+void GPC_RenderTools::EnableOpenGLLights()
+{
+ glEnable(GL_LIGHTING);
+ glEnable(GL_COLOR_MATERIAL);
+ glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE);
+ if (bgl::QueryExtension(bgl::_GL_EXT_separate_specular_color) || bgl::QueryVersion(1, 2))
+ glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
+}
+
+void GPC_RenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode,
+ const char* text,
+ int xco,
+ int yco,
+ int width,
+ int height)
+{
+ STR_String tmpstr(text);
+ int lines;
+ char* s = tmpstr.Ptr();
+ char* p;
+
+
+ // Save and change OpenGL settings
+ int texture2D;
+ glGetIntegerv(GL_TEXTURE_2D, (GLint*)&texture2D);
+ glDisable(GL_TEXTURE_2D);
+ int fog;
+ glGetIntegerv(GL_FOG, (GLint*)&fog);
+ glDisable(GL_FOG);
+
+ int light;
+ glGetIntegerv(GL_LIGHTING, (GLint*)&light);
+ glDisable(GL_LIGHTING);
+
+
+ // Set up viewing settings
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0, width, 0, height, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ // Actual drawing
+ unsigned char colors[2][3] = {
+ {0x00, 0x00, 0x00},
+ {0xFF, 0xFF, 0xFF}
+ };
+ int numTimes = mode == RAS_TEXT_PADDED ? 2 : 1;
+ for (int i = 0; i < numTimes; i++) {
+ glColor3ub(colors[i][0], colors[i][1], colors[i][2]);
+ glRasterPos2i(xco, yco);
+ for (p = s, lines = 0; *p; p++) {
+ if (*p == '\n')
+ {
+ lines++;
+ glRasterPos2i(xco, yco-(lines*18));
+ }
+ BMF_DrawCharacter(m_font, *p);
+ }
+ xco += 1;
+ yco += 1;
+ }
+
+ // Restore view settings
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ // Restore OpenGL Settings
+ if (fog)
+ glEnable(GL_FOG);
+ else
+ glDisable(GL_FOG);
+
+ if (texture2D)
+ glEnable(GL_TEXTURE_2D);
+ else
+ glDisable(GL_TEXTURE_2D);
+ if (light)
+ glEnable(GL_LIGHTING);
+ else
+ glDisable(GL_LIGHTING);
+}
+
+/**
+ * Copied from KX_BlenderRenderTools.cpp in KX_blenderhook
+ * Renders text into a (series of) polygon(s), using a texture font,
+ * Each character consists of one polygon (one quad or two triangles)
+ */
+void GPC_RenderTools::RenderText(
+ int mode,
+ RAS_IPolyMaterial* polymat,
+ float v1[3], float v2[3], float v3[3], float v4[3])
+{
+ STR_String mytext = ((CValue*)m_clientobject)->GetPropertyText("Text");
+
+ const unsigned int flag = polymat->GetFlag();
+ struct MTFace* tface = 0;
+ unsigned int* col = 0;
+
+ if(flag & RAS_BLENDERMAT) {
+ KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(polymat);
+ tface = bl_mat->GetMTFace();
+ col = bl_mat->GetMCol();
+ } else {
+ KX_PolygonMaterial* blenderpoly = static_cast<KX_PolygonMaterial*>(polymat);
+ tface = blenderpoly->GetMTFace();
+ col = blenderpoly->GetMCol();
+ }
+
+ BL_RenderText(mode, mytext, mytext.Length(), tface, col, v1, v2, v3, v4);
+}
+
+
+
+/**
+ * Copied from KX_BlenderGL.cpp in KX_blenderhook
+ */
+void GPC_RenderTools::BL_RenderText(
+ int mode,
+ const char* textstr,
+ int textlen,
+ struct MTFace* tface,
+ unsigned int* col,
+ float v1[3],float v2[3],float v3[3],float v4[3])
+{
+ struct Image* ima;
+
+ if (mode & TF_BMFONT) {
+ //char string[MAX_PROPSTRING];
+// float tmat[4][4];
+ int characters, index, character;
+ float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
+
+// bProperty *prop;
+
+ // string = "Frank van Beek";
+
+ characters = textlen;
+
+ ima = (struct Image*) tface->tpage;
+ if (ima == NULL) {
+ characters = 0;
+ }
+
+ if(!col) glColor3f(1.0f, 1.0f, 1.0f);
+
+ glPushMatrix();
+ for (index = 0; index < characters; index++) {
+ // lets calculate offset stuff
+ character = textstr[index];
+
+ // space starts at offset 1
+ // character = character - ' ' + 1;
+
+ matrixGlyph((ImBuf *)ima->ibufs.first, character, & centerx, &centery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
+
+ glBegin(GL_POLYGON);
+ // printf(" %c %f %f %f %f\n", character, tface->uv[0][0], tface->uv[0][1], );
+ // glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy);
+ glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy);
+
+ if(col) BL_spack(col[0]);
+ // glVertex3fv(v1);
+ 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(col) BL_spack(col[1]);
+ // glVertex3fv(v2);
+ 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(col) BL_spack(col[2]);
+ // glVertex3fv(v3);
+ glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
+
+ if(v4) {
+ // glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, 1.0 - (1.0 - tface->uv[3][1]) * sizey - transy);
+ glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, (tface->uv[3][1] - centery) * sizey + transy);
+ if(col) BL_spack(col[3]);
+ // glVertex3fv(v4);
+ glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
+ }
+ glEnd();
+
+ glTranslatef(advance, 0.0, 0.0);
+ }
+ glPopMatrix();
+
+ }
+}
+
+
+RAS_IPolyMaterial* GPC_RenderTools::CreateBlenderPolyMaterial(
+ const STR_String &texname,
+ bool ba,const STR_String& matname,int tile,int tilexrep,int tileyrep,int mode,bool transparant, bool zsort,
+ int lightlayer,bool bIsTriangle,void* clientobject,void* tface)
+{
+ assert(!"Deprecated");
+/* return new GPC_PolygonMaterial(texname, ba,matname,tile,tilexrep,tileyrep,
+ mode,transparant,zsort,lightlayer,bIsTriangle,clientobject,tface);
+ */
+ return NULL;
+}
+
+
+int GPC_RenderTools::applyLights(int objectlayer)
+{
+// taken from blender source, incompatibility between Blender Object / GameObject
+
+ int count;
+ float vec[4];
+
+ vec[3]= 1.0;
+
+ for(count=0; count<m_numgllights; count++)
+ glDisable((GLenum)(GL_LIGHT0+count));
+
+ //std::vector<struct RAS_LightObject*> m_lights;
+ std::vector<struct RAS_LightObject*>::iterator lit = m_lights.begin();
+
+
+ for (lit = m_lights.begin(), count = 0; !(lit==m_lights.end()) && count < m_numgllights; ++lit)
+ {
+ RAS_LightObject* lightdata = (*lit);
+ if (lightdata->m_layer & objectlayer)
+ {
+
+ glPushMatrix();
+ glLoadMatrixf(m_viewmat);
+
+
+ vec[0] = (*(lightdata->m_worldmatrix))(0,3);
+ vec[1] = (*(lightdata->m_worldmatrix))(1,3);
+ vec[2] = (*(lightdata->m_worldmatrix))(2,3);
+ vec[3] = 1;
+
+
+ if(lightdata->m_type==RAS_LightObject::LIGHT_SUN) {
+
+ vec[0] = (*(lightdata->m_worldmatrix))(0,2);
+ vec[1] = (*(lightdata->m_worldmatrix))(1,2);
+ vec[2] = (*(lightdata->m_worldmatrix))(2,2);
+ //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((GLenum)(GL_LIGHT0+count), GL_POSITION, vec);
+ }
+ else {
+ //vec[3]= 1.0;
+ glLightfv((GLenum)(GL_LIGHT0+count), GL_POSITION, vec);
+ glLightf((GLenum)(GL_LIGHT0+count), GL_CONSTANT_ATTENUATION, 1.0);
+ glLightf((GLenum)(GL_LIGHT0+count), GL_LINEAR_ATTENUATION, lightdata->m_att1/lightdata->m_distance);
+ // without this next line it looks backward compatible.
+ //attennuation still is acceptable
+ glLightf((GLenum)(GL_LIGHT0+count), GL_QUADRATIC_ATTENUATION, lightdata->m_att2/(lightdata->m_distance*lightdata->m_distance));
+
+ if(lightdata->m_type==RAS_LightObject::LIGHT_SPOT) {
+ vec[0] = -(*(lightdata->m_worldmatrix))(0,2);
+ vec[1] = -(*(lightdata->m_worldmatrix))(1,2);
+ vec[2] = -(*(lightdata->m_worldmatrix))(2,2);
+ //vec[0]= -base->object->obmat[2][0];
+ //vec[1]= -base->object->obmat[2][1];
+ //vec[2]= -base->object->obmat[2][2];
+ glLightfv((GLenum)(GL_LIGHT0+count), GL_SPOT_DIRECTION, vec);
+ glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_CUTOFF, lightdata->m_spotsize/2.0);
+ glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_EXPONENT, 128.0*lightdata->m_spotblend);
+ }
+ else glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_CUTOFF, 180.0);
+ }
+
+ if (lightdata->m_nodiffuse)
+ {
+ vec[0] = vec[1] = vec[2] = vec[3] = 0.0;
+ } else {
+ vec[0]= lightdata->m_energy*lightdata->m_red;
+ vec[1]= lightdata->m_energy*lightdata->m_green;
+ vec[2]= lightdata->m_energy*lightdata->m_blue;
+ vec[3]= 1.0;
+ }
+ glLightfv((GLenum)(GL_LIGHT0+count), GL_DIFFUSE, vec);
+ if (lightdata->m_nospecular)
+ {
+ vec[0] = vec[1] = vec[2] = vec[3] = 0.0;
+ } else if (lightdata->m_nodiffuse) {
+ vec[0]= lightdata->m_energy*lightdata->m_red;
+ vec[1]= lightdata->m_energy*lightdata->m_green;
+ vec[2]= lightdata->m_energy*lightdata->m_blue;
+ vec[3]= 1.0;
+ }
+ glLightfv((GLenum)(GL_LIGHT0+count), GL_SPECULAR, vec);
+ glEnable((GLenum)(GL_LIGHT0+count));
+
+ count++;
+
+ glPopMatrix();
+ }
+ }
+
+ return count;
+
+}
+
+bool GPC_RenderTools::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data)
+{
+ double* const oglmatrix = (double* const) data;
+ MT_Point3 resultpoint(hit_point);
+ MT_Vector3 resultnormal(hit_normal);
+ MT_Vector3 left(oglmatrix[0],oglmatrix[1],oglmatrix[2]);
+ MT_Vector3 dir = -(left.cross(resultnormal)).safe_normalized();
+ left = (dir.cross(resultnormal)).safe_normalized();
+ // for the up vector, we take the 'resultnormal' returned by the physics
+
+ double maat[16]={
+ left[0], left[1], left[2], 0,
+ dir[0], dir[1], dir[2], 0,
+ resultnormal[0],resultnormal[1],resultnormal[2], 0,
+ 0, 0, 0, 1};
+ glTranslated(resultpoint[0],resultpoint[1],resultpoint[2]);
+ //glMultMatrixd(oglmatrix);
+ glMultMatrixd(maat);
+ return true;
+}
+
+void GPC_RenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmatrix,int objectdrawmode )
+{
+ if (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED ||
+ objectdrawmode & RAS_IPolyMaterial::BILLBOARD_AXISALIGNED)
+ {
+ // rotate the billboard/halo
+ //page 360/361 3D Game Engine Design, David Eberly for a discussion
+ // on screen aligned and axis aligned billboards
+ // assumed is that the preprocessor transformed all billboard polygons
+ // so that their normal points into the positive x direction (1.0 , 0.0 , 0.0)
+ // when new parenting for objects is done, this rotation
+ // will be moved into the object
+
+ MT_Point3 objpos (oglmatrix[12],oglmatrix[13],oglmatrix[14]);
+ MT_Point3 campos = rasty->GetCameraPosition();
+ MT_Vector3 dir = (campos - objpos).safe_normalized();
+ MT_Vector3 up(0,0,1.0);
+
+ KX_GameObject* gameobj = (KX_GameObject*) this->m_clientobject;
+ // get scaling of halo object
+ MT_Vector3 size = gameobj->GetSGNode()->GetLocalScale();
+
+ bool screenaligned = (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED)!=0;//false; //either screen or axisaligned
+ if (screenaligned)
+ {
+ up = (up - up.dot(dir) * dir).safe_normalized();
+ } else
+ {
+ dir = (dir - up.dot(dir)*up).safe_normalized();
+ }
+
+ MT_Vector3 left = dir.normalized();
+ dir = (left.cross(up)).normalized();
+
+ // we have calculated the row vectors, now we keep
+ // local scaling into account:
+
+ left *= size[0];
+ dir *= size[1];
+ up *= size[2];
+ double maat[16]={
+ left[0], left[1],left[2], 0,
+ dir[0], dir[1],dir[2],0,
+ up[0],up[1],up[2],0,
+ 0,0,0,1};
+ glTranslated(objpos[0],objpos[1],objpos[2]);
+ glMultMatrixd(maat);
+
+ } else
+ {
+ if (objectdrawmode & RAS_IPolyMaterial::SHADOW)
+ {
+ // shadow must be cast to the ground, physics system needed here!
+ MT_Point3 frompoint(oglmatrix[12],oglmatrix[13],oglmatrix[14]);
+ KX_GameObject *gameobj = (KX_GameObject*) this->m_clientobject;
+ MT_Vector3 direction = MT_Vector3(0,0,-1);
+
+ direction.normalize();
+ direction *= 100000;
+
+ MT_Point3 topoint = frompoint + direction;
+
+ KX_Scene* kxscene = (KX_Scene*) m_auxilaryClientInfo;
+ PHY_IPhysicsEnvironment* physics_environment = kxscene->GetPhysicsEnvironment();
+ KX_IPhysicsController* physics_controller = gameobj->GetPhysicsController();
+
+ KX_GameObject *parent = gameobj->GetParent();
+ if (!physics_controller && parent)
+ physics_controller = parent->GetPhysicsController();
+ if (parent)
+ parent->Release();
+
+ MT_Point3 resultpoint;
+ MT_Vector3 resultnormal;
+ if (!KX_RayCast::RayTest(physics_controller, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<GPC_RenderTools>(this, oglmatrix)))
+ {
+ // couldn't find something to cast the shadow on...
+ glMultMatrixd(oglmatrix);
+ }
+ } else
+ {
+
+ // 'normal' object
+ glMultMatrixd(oglmatrix);
+ }
+ }
+}
+
+void GPC_RenderTools::MotionBlur(RAS_IRasterizer* rasterizer)
+{
+ int state = rasterizer->GetMotionBlurState();
+ float motionblurvalue;
+ if(state)
+ {
+ motionblurvalue = rasterizer->GetMotionBlurValue();
+ if(state==1)
+ {
+ //bugfix:load color buffer into accum buffer for the first time(state=1)
+ glAccum(GL_LOAD, 1.0);
+ rasterizer->SetMotionBlurState(2);
+ }
+ else if(motionblurvalue>=0.0 && motionblurvalue<=1.0)
+ {
+ glAccum(GL_MULT, motionblurvalue);
+ glAccum(GL_ACCUM, 1-motionblurvalue);
+ glAccum(GL_RETURN, 1.0);
+ glFlush();
+ }
+ }
+}
+
+unsigned int GPC_RenderTools::m_numgllights;
diff --git a/source/gameengine/GamePlayer/common/GPC_RenderTools.h b/source/gameengine/GamePlayer/common/GPC_RenderTools.h
new file mode 100644
index 00000000000..e1f2a869c22
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_RenderTools.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 __GPC_RENDERTOOLS_H
+#define __GPC_RENDERTOOLS_H
+
+#if defined(WIN32) || defined(__APPLE__)
+ #ifdef WIN32
+ #include <windows.h>
+ #include <GL/gl.h>
+ #else // WIN32
+ // __APPLE__ is defined
+ #include <AGL/gl.h>
+ #endif // WIN32
+#else //defined(WIN32) || defined(__APPLE__)
+ #include <GL/gl.h>
+#endif //defined(WIN32) || defined(__APPLE__)
+
+
+#include "RAS_IRenderTools.h"
+
+#include "BMF_Api.h"
+
+struct KX_ClientObjectInfo;
+
+
+class GPC_RenderTools : public RAS_IRenderTools
+{
+public:
+ GPC_RenderTools();
+ virtual ~GPC_RenderTools();
+
+ virtual void EndFrame(RAS_IRasterizer* rasty);
+ virtual void BeginFrame(RAS_IRasterizer* rasty);
+
+ void DisableOpenGLLights()
+ {
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ }
+
+ void EnableOpenGLLights();
+
+ int ProcessLighting(int layer);
+
+ void Perspective(int a, int width, int height, float mat[4][4], float viewmat[4][4])
+ {
+ if(a== 0)
+ {
+ glMatrixMode(GL_PROJECTION);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ }
+ else
+ {
+ if(a== 1)
+ {
+ glMatrixMode(GL_PROJECTION);
+ glMatrixMode(GL_MODELVIEW);
+ }
+ }
+ }
+
+ /**
+ * @attention mode is ignored here
+ */
+ virtual void RenderText2D(
+ RAS_TEXT_RENDER_MODE mode,
+ const char* text,
+ int xco,
+ int yco,
+ int width,
+ int height);
+
+ /**
+ * Renders text into a (series of) polygon(s), using a texture font,
+ * Each character consists of one polygon (one quad or two triangles)
+ */
+ virtual void RenderText(
+ int mode,
+ RAS_IPolyMaterial* polymat,
+ float v1[3],
+ float v2[3],
+ float v3[3],
+ float v4[3]);
+
+ void Render(RAS_IRasterizer* rasty,double* oglmatrix,int objectdrawmode)
+ {
+ glPopMatrix();
+ glPushMatrix();
+ glMultMatrixd(oglmatrix);
+ }
+
+ void applyTransform(RAS_IRasterizer* rasty, double* oglmatrix, int objectdrawmode);
+
+ virtual void PushMatrix()
+ {
+ glPushMatrix();
+ }
+
+ virtual void PopMatrix()
+ {
+ glPopMatrix();
+ }
+
+ virtual class RAS_IPolyMaterial* CreateBlenderPolyMaterial(
+ const STR_String &texname,
+ bool ba,
+ const STR_String& matname,
+ int tile,
+ int tilexrep,int tileyrep,
+ int mode,
+ bool transparant,
+ bool zsort,
+ int lightlayer,
+ bool bIsTriangle,
+ void* clientobject,
+ void* tface);
+
+ int applyLights(int objectlayer);
+
+ bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data);
+
+ virtual void MotionBlur(RAS_IRasterizer* rasterizer);
+protected:
+ /**
+ * Copied from KX_BlenderGL.cpp in KX_blenderhook
+ */
+ void BL_RenderText(
+ int mode,
+ const char* textstr,
+ int textlen,
+ struct MTFace* tface,
+ unsigned int* col,
+ float v1[3],float v2[3],float v3[3],float v4[3]);
+ void BL_spack(unsigned int ucol)
+ {
+ char *cp = (char *)&ucol;
+ glColor3ub(cp[3], cp[2], cp[1]);
+ }
+
+
+ BMF_Font* m_font;
+ static unsigned int m_numgllights;
+};
+
+#endif // __GPC_RENDERTOOLS_H
+
+
diff --git a/source/gameengine/GamePlayer/common/GPC_System.cpp b/source/gameengine/GamePlayer/common/GPC_System.cpp
new file mode 100644
index 00000000000..31393505796
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_System.cpp
@@ -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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "GPC_System.h"
+
+#include "GPC_KeyboardDevice.h"
+#include "NG_NetworkDeviceInterface.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+GPC_System::GPC_System()
+// : m_ndi(0)
+{
+}
+
+/*
+void GPC_System::NextFrame()
+{
+ // Have the imput devices proceed
+ std::vector<SCA_IInputDevice*>::iterator idev;
+ for (idev = m_inputDevices.begin(); !(idev == m_inputDevices.end()); idev++) {
+ (*idev)->NextFrame();
+ }
+
+ // Have the network device proceed
+ if (m_ndi) {
+ m_ndi->NextFrame();
+ }
+}
+
+void GPC_System::StartMainLoop()
+{
+}
+
+
+void GPC_System::Sleep(int millisec)
+{
+ // do nothing for now ;)
+}
+
+
+void GPC_System::AddKey(unsigned char key, bool down)
+{
+ GPC_KeyboardDevice* keydev = (GPC_KeyboardDevice*) this->GetKeyboardDevice();
+ if (keydev) {
+ //SCA_IInputDevice::KX_EnumInputs inp = keydev->ToNative(key);
+ keydev->ConvertEvent(key, down);
+ }
+}
+
+
+void GPC_System::SetNetworkDevice(NG_NetworkDeviceInterface* ndi)
+{
+ m_ndi = ndi;
+}
+
+
+NG_NetworkDeviceInterface* GPC_System::GetNetworkDevice() const
+{
+ return m_ndi;
+}
+*/
diff --git a/source/gameengine/GamePlayer/common/GPC_System.h b/source/gameengine/GamePlayer/common/GPC_System.h
new file mode 100644
index 00000000000..e102341749d
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/GPC_System.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef __GPC_SYSTEM_H
+#define __GPC_SYSTEM_H
+
+#if defined(WIN32)
+#pragma warning (disable:4786) // suppress stl-MSVC debug info warning
+#endif /* WIN32 */
+
+#include "KX_ISystem.h"
+
+//class NG_NetworkDeviceInterface;
+
+class GPC_System : public KX_ISystem
+{
+public:
+ GPC_System();
+
+// virtual void NextFrame();
+// virtual void StartMainLoop();
+ virtual double GetTimeInSeconds() = 0;
+// virtual void Sleep(int millisec);
+ //virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode);
+// void AddKey(unsigned char key, bool down);
+
+// virtual void SetNetworkDevice(NG_NetworkDeviceInterface* ndi);
+// virtual NG_NetworkDeviceInterface* GetNetworkDevice() const;
+
+//protected:
+// NG_NetworkDeviceInterface* m_ndi;
+};
+
+#endif // __GPC_SYSTEM_H
+
diff --git a/source/gameengine/GamePlayer/common/Makefile b/source/gameengine/GamePlayer/common/Makefile
new file mode 100644
index 00000000000..5b61fb4f902
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/Makefile
@@ -0,0 +1,89 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by 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 = common
+DIR = $(OCGDIR)/gameengine/GamePlayer/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+
+CPPFLAGS += -I../../../blender/blenkernel
+CPPFLAGS += -I../../../blender/blenloader
+CPPFLAGS += -I../../../blender/blenlib
+CPPFLAGS += -I../../../blender/imbuf
+CPPFLAGS += -I../../../blender/makesdna
+CPPFLAGS += -I../../../kernel/gen_system
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+
+CPPFLAGS += -I$(NAN_FUZZICS)/include
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_SUMO)/include
+CPPFLAGS += -I$(NAN_SOLID)/include
+CPPFLAGS += -I$(NAN_PNG)/include
+CPPFLAGS += -I$(NAN_ZLIB)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+CPPFLAGS += -I$(NAN_BMFONT)/include
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include
+CPPFLAGS += -I../../../gameengine/Converter
+CPPFLAGS += -I../../../gameengine/Expressions
+CPPFLAGS += -I../../../gameengine/GameLogic
+CPPFLAGS += -I../../../gameengine/Converter
+CPPFLAGS += -I../../../gameengine/Ketsji
+CPPFLAGS += -I../../../gameengine/Ketsji/KXNetwork
+CPPFLAGS += -I../../../gameengine/Network
+CPPFLAGS += -I../../../gameengine/Network/LoopBackNetwork
+CPPFLAGS += -I../../../gameengine/Rasterizer
+CPPFLAGS += -I../../../gameengine/SceneGraph
+CPPFLAGS += -I../../../gameengine/Rasterizer/RAS_OpenGLRasterizer
+CPPFLAGS += -I../../../gameengine/Physics/Sumo
+CPPFLAGS += -I../../../gameengine/Physics/common
+
+###############################
+
+SOURCEDIR = source/gameengine/GamePlayer/common
+DIRS =
+ifeq ($(OS),windows)
+# Still
+ DIRS = windows
+else
+ ifneq ($(OS),darwin)
+ DIRS = unix
+ endif
+endif
+
+include nan_subdirs.mk
diff --git a/source/gameengine/GamePlayer/common/SConscript b/source/gameengine/GamePlayer/common/SConscript
new file mode 100644
index 00000000000..944fcea3a51
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/SConscript
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+import sys
+Import ('env')
+
+
+source_files = ['bmfont.cpp',
+ 'GPC_Canvas.cpp',
+ 'GPC_Engine.cpp',
+ 'GPC_KeyboardDevice.cpp',
+ 'GPC_MouseDevice.cpp',
+ 'GPC_PolygonMaterial.cpp',
+ 'GPC_RawImage.cpp',
+ 'GPC_RawLoadDotBlendArray.cpp',
+ 'GPC_RawLogoArrays.cpp',
+ 'GPC_RenderTools.cpp',
+ 'GPC_System.cpp']
+
+incs = ['.',
+ '#intern/string',
+ '#intern/ghost',
+ '#intern/guardedalloc',
+ '#intern/bmfont',
+ '#intern/moto/include',
+ '#intern/SoundSystem',
+ '#source/gameengine/Rasterizer/RAS_OpenGLRasterizer',
+ '#source/kernel/gen_system',
+ '#source/kernel/gen_messaging',
+ '#source/gameengine/Converter',
+ '#source/blender/imbuf',
+ '#source/gameengine/Ketsji',
+ '#source/blender/blenlib',
+ '#source/blender/blenkernel',
+ '#source/blender',
+ '#source/blender/include',
+ '#source/blender/makesdna',
+ '#source/gameengine/Rasterizer',
+ '#source/gameengine/GameLogic',
+ '#source/gameengine/Expressions',
+ '#source/gameengine/Network',
+ '#source/gameengine/SceneGraph',
+ '#source/gameengine/Physics/common',
+ '#source/gameengine/Physics/Sumo',
+ '#source/gameengine/Physics/Sumo/Fuzzics/include',
+ '#source/gameengine/Network/LoopBackNetwork',
+ '#source/gameengine/GamePlayer/ghost',
+ '#source/blender/misc',
+ '#source/blender/blenloader']
+
+#This is all plugin stuff!
+#if sys.platform=='win32':
+# source_files += ['windows/GPW_Canvas.cpp',
+# 'windows/GPW_Engine.cpp',
+# 'windows/GPW_KeyboardDevice.cpp',
+# 'windows/GPW_System.cpp']
+# gp_common_env.Append ( CPPPATH = ['windows'])
+#elif sys.platform=='linux2' or sys.platform=='linux-i386':
+# source_files += ['unix/GPU_Canvas.cpp',
+# 'unix/GPU_Engine.cpp',
+# 'unix/GPU_KeyboardDevice.cpp',
+# 'unix/GPU_System.cpp']
+# gp_common_env.Append ( CPPPATH = ['unix'])
+
+incs += Split(env['BF_PYTHON_INC'])
+incs += Split(env['BF_SOLID_INC'])
+incs += Split(env['BF_PNG_INC'])
+incs += Split(env['BF_ZLIB_INC'])
+
+cflags=[]
+if env['OURPLATFORM']=='win32-vc':
+ cflags = ['/GR']
+
+env.BlenderLib (libname='gp_common', sources=source_files, includes=incs, defines = [], libtype='player', priority=5, compileflags=cflags)
diff --git a/source/gameengine/GamePlayer/common/bmfont.cpp b/source/gameengine/GamePlayer/common/bmfont.cpp
new file mode 100644
index 00000000000..c98c85bc272
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/bmfont.cpp
@@ -0,0 +1,305 @@
+/**
+ * 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
+
+/*MAART:
+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 = (unsigned char*)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 = (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++];
+ /* MAART:
+ if (G.f & G_DEBUG) {
+ printfGlyph(&bmfont->glyphs[i]);
+ }
+ */
+ }
+
+ MEM_freeN(buffer);
+
+ /* MAART:
+ 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 {
+ /* MAART:
+ 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 = (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 = (float)(1.0 - *sizey + 2.0 * (bmfont->glyphs[index].ofsy - bmfont->glyphs[0].ofsy) / (float) bmfont->glyphs[0].sizey);
+ *movex = (float)(*sizex - 1.0 + 2.0 * (bmfont->glyphs[index].ofsx - bmfont->glyphs[0].ofsx) / (float) bmfont->glyphs[0].sizex);
+
+ *advance = (float)(2.0 * 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/gameengine/GamePlayer/common/load.blend b/source/gameengine/GamePlayer/common/load.blend
new file mode 100644
index 00000000000..ae520504971
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/load.blend
Binary files differ
diff --git a/source/gameengine/GamePlayer/common/logo_blender.raw b/source/gameengine/GamePlayer/common/logo_blender.raw
new file mode 100644
index 00000000000..82bf25a2c6e
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/logo_blender.raw
Binary files differ
diff --git a/source/gameengine/GamePlayer/common/logo_blender3d.raw b/source/gameengine/GamePlayer/common/logo_blender3d.raw
new file mode 100644
index 00000000000..6a86626bb10
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/logo_blender3d.raw
Binary files differ
diff --git a/source/gameengine/GamePlayer/common/logo_nan.raw b/source/gameengine/GamePlayer/common/logo_nan.raw
new file mode 100644
index 00000000000..b86308bd017
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/logo_nan.raw
Binary files differ
diff --git a/source/gameengine/GamePlayer/common/unix/GPU_Canvas.cpp b/source/gameengine/GamePlayer/common/unix/GPU_Canvas.cpp
new file mode 100644
index 00000000000..d393f4196aa
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/unix/GPU_Canvas.cpp
@@ -0,0 +1,75 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 <iostream>
+#include "GPU_Canvas.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+GPU_Canvas::GPU_Canvas(KXH_plugin_handle p, int width, int height)
+ : GPC_Canvas(width, height), m_plugin(p)
+{
+ /* intentionally empty */
+}
+
+
+GPU_Canvas::~GPU_Canvas(void)
+{
+ /* intentionally empty */
+}
+
+void GPU_Canvas::Init(void)
+{
+ /* intentionally empty */
+}
+
+void GPU_Canvas::SwapBuffers(void)
+{
+ if (m_plugin) KXH_swap_buffers(m_plugin);
+}
+
+bool
+GPU_Canvas::BeginDraw(void)
+{
+ if (m_plugin) {
+ return KXH_begin_draw(m_plugin);
+ } else {
+ return false;
+ }
+}
+
+void GPU_Canvas::EndDraw(void)
+{
+ if (m_plugin) KXH_end_draw(m_plugin);
+}
diff --git a/source/gameengine/GamePlayer/common/unix/GPU_Canvas.h b/source/gameengine/GamePlayer/common/unix/GPU_Canvas.h
new file mode 100644
index 00000000000..6ff1935d9c1
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/unix/GPU_Canvas.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 __GPU_CANVAS_H
+#define __GPU_CANVAS_H
+
+#include <iostream>
+
+#include "KXH_ketsji_hooks.h"
+#include "GPC_Canvas.h"
+
+class GPU_Canvas : public GPC_Canvas
+{
+private:
+
+ /** Handle to the drawing resource. */
+ KXH_plugin_handle m_plugin;
+
+public:
+ GPU_Canvas(KXH_plugin_handle display, int width, int height);
+ virtual ~GPU_Canvas();
+
+ virtual void Init(void);
+
+ bool BeginDraw(void);
+ void EndDraw(void);
+ virtual void SwapBuffers(void);
+
+};
+
+#endif // __GPU_CANVAS_H
+
diff --git a/source/gameengine/GamePlayer/common/unix/GPU_Engine.cpp b/source/gameengine/GamePlayer/common/unix/GPU_Engine.cpp
new file mode 100644
index 00000000000..41186a590f5
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/unix/GPU_Engine.cpp
@@ -0,0 +1,309 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 <assert.h>
+#include <unistd.h>
+#include "GPU_Engine.h"
+#include "GPC_MouseDevice.h"
+#include "GPU_Canvas.h"
+#include "GPU_KeyboardDevice.h"
+#include "GPU_System.h"
+
+#include "BLI_blenlib.h"
+#include "BLO_readfile.h"
+
+#include "SND_DeviceManager.h"
+
+#include "NG_NetworkScene.h"
+#include "NG_LoopBackNetworkDeviceInterface.h"
+#include "SND_DeviceManager.h"
+#include "KX_BlenderSceneConverter.h"
+#ifdef USE_SUMO_SOLID
+ #include "SM_Scene.h"
+#endif
+#include "KX_KetsjiEngine.h"
+
+#include "GPC_RenderTools.h"
+#include "GPC_RawImage.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void Redraw(GPU_Engine *engine); // -the- redraw function
+
+// callback functions
+/*
+void RedrawCallback(Widget, XtPointer closure, XEvent *, Boolean *continue_to_dispatch);
+
+void KeyDownCallback(Widget w, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
+void KeyUpCallback(Widget w, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
+
+void ButtonPressReleaseCallback(Widget w, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
+void PointerMotionCallback(Widget w, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
+
+void TimeOutCallback(XtPointer closure, XtIntervalId *id);
+*/
+
+GPU_Engine::GPU_Engine(char *customLoadingAnimationURL,
+ int foregroundColor, int backgroundColor, int frameRate) :
+ GPC_Engine(customLoadingAnimationURL, foregroundColor, backgroundColor,
+ frameRate), m_timerTimeOutMsecs(10)
+{
+}
+
+
+GPU_Engine::~GPU_Engine()
+{
+}
+
+/*
+bool GPU_Engine::Initialize(Display *display, Window window, int width, int height)
+{
+ SND_DeviceManager::Subscribe();
+ m_audiodevice = SND_DeviceManager::Instance();
+
+ m_keyboarddev = new GPU_KeyboardDevice();
+ m_mousedev = new GPC_MouseDevice();
+
+ // constructor only initializes data
+ // m_canvas = new GPU_Canvas(display, window, width, height);
+ //m_canvas->Init(); // create the actual visual and rendering context
+ //cout << "GPU_Canvas created and initialized, m_canvas " << m_canvas << endl;
+ //AddEventHandlers(); // done here (in GPU_Engine) since the event handlers need access to 'this', ie the engine
+
+ // put the Blender logo in the topleft corner
+ if(m_BlenderLogo != 0)
+ // adding a banner automatically enables them
+ m_BlenderLogoId = m_canvas->AddBanner(m_BlenderLogo->Width(), m_BlenderLogo->Height(),
+ m_BlenderLogo->Width(), m_BlenderLogo->Height(),
+ m_BlenderLogo->Data(), GPC_Canvas::alignTopLeft);
+
+ // put the Blender3D logo in the bottom right corner
+ if(m_Blender3DLogo != 0)
+ // adding a banner automatically enables them
+ m_Blender3DLogoId = m_canvas->AddBanner(m_Blender3DLogo->Width(), m_Blender3DLogo->Height(),
+ m_Blender3DLogo->Width(), m_Blender3DLogo->Height(),
+ m_Blender3DLogo->Data(), GPC_Canvas::alignTopLeft);
+
+#if 0
+ // put the NaN logo in the bottom right corner
+ if(m_NaNLogo != 0)
+ // adding a banner automatically enables them
+ m_NaNLogoId = m_canvas->AddBanner(m_NaNLogo->Width(), m_NaNLogo->Height(),
+ m_NaNLogo->Width(), m_NaNLogo->Height(),
+ m_NaNLogo->Data(), GPC_Canvas::alignBottomRight);
+#endif
+ // enable the display of all banners
+ m_canvas->SetBannerDisplayEnabled(true);
+
+ m_rendertools = new GPC_RenderTools();
+
+ m_networkdev = new NG_LoopBackNetworkDeviceInterface();
+ assert(m_networkdev);
+
+ // creation of system needs 'current rendering context', this is taken care
+ // of by the GPU_Canvas::Init()
+ m_system = new GPU_System();
+
+ m_system->SetKeyboardDevice((GPU_KeyboardDevice *)m_keyboarddev);
+ m_system->SetMouseDevice(m_mousedev);
+ m_system->SetNetworkDevice(m_networkdev);
+
+ m_initialized = true;
+
+ return m_initialized;
+}
+*/
+
+/*
+void GPU_Engine::HandleNewWindow(Window window)
+{
+ // everything only if it's really a new window
+ if(window != ((GPU_Canvas *)m_canvas)->GetWindow())
+ {
+ cout << "GPU_Engine::HandleNewWindow(), new window so calling SetNewWindowMakeNewWidgetAndMakeCurrent()" << endl;
+ // We don't have to remove the event handlers ourselves, they are destroyed by X11
+
+ // make canvas aware of new window, and make it current
+ ((GPU_Canvas *)m_canvas)->SetNewWindowMakeNewWidgetAndMakeCurrent(window);
+
+ // and add event handlers to new widget
+ AddEventHandlers();
+ cout << "GPU_Engine::HandleNewWindow(), event handlers added" << endl;
+ }
+}
+*/
+/*
+void GPU_Engine::AddEventHandlers(void)
+{
+ Widget widget = ((GPU_Canvas *)m_canvas)->GetWidget();
+
+ // redraw
+ // MUST be the *Raw* event handler, the normal one doesn't work!
+ XtAddRawEventHandler(widget, ExposureMask, FALSE, RedrawCallback, this);
+#if 0
+ // key down
+ XtAddRawEventHandler(widget, KeyPressMask, FALSE, KeyDownCallback, this);
+ // key up
+ XtAddRawEventHandler(widget, KeyReleaseMask, FALSE, KeyUpCallback, this);
+
+ // mouse button press
+ XtAddRawEventHandler(widget, ButtonPressMask, FALSE, ButtonPressReleaseCallback, this);
+ // mouse button release
+ XtAddRawEventHandler(widget, ButtonReleaseMask, FALSE, ButtonPressReleaseCallback, this);
+ // mouse motion
+ XtAddRawEventHandler(widget, PointerMotionMask, FALSE, PointerMotionCallback, this);
+#endif
+#if 0
+ // time out, not a real timer. New time out will be set in callback
+ m_timerId = XtAppAddTimeOut(XtWidgetToApplicationContext(widget),
+ m_timerTimeOutMsecs, TimeOutCallback, this);
+#endif
+}
+*/
+
+void Redraw(GPU_Engine *engine)
+{
+/* if(engine->Running())
+ {
+ if(engine->Loading())
+ {
+ engine->UpdateLoadingAnimation();
+ }
+
+ engine->m_system->DoMainLoopCallback();
+ }*/
+}
+
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++
+ * Callback functions
+ +++++++++++++++++++++++++++++++++++++++++++++++++*/
+void RedrawCallback(Widget, XtPointer closure, XEvent *, Boolean *continue_to_dispatch)
+{
+ GPU_Engine *engine = (GPU_Engine *)closure;
+
+ Redraw(engine);
+
+ *continue_to_dispatch = True;
+}
+
+
+void KeyDownCallback(Widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
+{
+/* GPU_Engine *engine = (GPU_Engine *)closure;
+ XKeyEvent *keyEvent = (XKeyEvent *)event;
+
+ if(engine->Running())
+ engine->m_system->AddKey(int(keyEvent->keycode), 1);
+
+ *continue_to_dispatch = True;*/
+}
+
+
+void KeyUpCallback(Widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
+{
+/* GPU_Engine *engine = (GPU_Engine *)closure;
+ XKeyEvent *keyEvent = (XKeyEvent *)event;
+
+ if(engine->Running())
+ engine->m_system->AddKey(int(keyEvent->keycode), 0);
+
+ *continue_to_dispatch = True;*/
+}
+
+
+void ButtonPressReleaseCallback(Widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
+{
+ GPU_Engine *engine = (GPU_Engine *)closure;
+ XButtonEvent *buttonEvent = (XButtonEvent *)event;
+ bool isDown;
+ GPC_MouseDevice::TButtonId button;
+
+ if(engine->Running())
+ {
+ // determine type of event, press or release
+ isDown = false;
+ if(buttonEvent->type == ButtonPress)
+ isDown = true;
+ // determine which button exactly generated this event
+ switch(buttonEvent->button)
+ {
+ case 1:
+ button = GPC_MouseDevice::buttonLeft;
+ break;
+ case 2:
+ button = GPC_MouseDevice::buttonMiddle;
+ break;
+ case 3:
+ button = GPC_MouseDevice::buttonRight;
+ break;
+ }
+ engine->m_mousedev->ConvertButtonEvent(button,
+ isDown, buttonEvent->x, buttonEvent->y);
+ }
+
+ *continue_to_dispatch = True;
+}
+
+
+void PointerMotionCallback(Widget w, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
+{
+ GPU_Engine *engine = (GPU_Engine *)closure;
+ XButtonEvent *buttonEvent = (XButtonEvent *)event;
+
+ if(engine->Running())
+ {
+ engine->m_mousedev->ConvertMoveEvent(buttonEvent->x, buttonEvent->y);
+ }
+
+ *continue_to_dispatch = True;
+}
+
+/*
+void TimeOutCallback(XtPointer closure, XtIntervalId *id)
+{
+ GPU_Engine *engine = (GPU_Engine *)closure;
+
+ Redraw(engine);
+ // add a new time out since there is no real timer for X (not a simple one like under windows)
+ // TODO Have to get faster timer !
+
+ if(engine->Running())
+ engine->m_timerId = XtAppAddTimeOut(XtWidgetToApplicationContext(
+ ((GPU_Canvas *)engine->m_canvas)->GetWidget()),
+ engine->m_timerTimeOutMsecs, TimeOutCallback,
+ closure);
+}
+
+*/
diff --git a/source/gameengine/GamePlayer/common/unix/GPU_Engine.h b/source/gameengine/GamePlayer/common/unix/GPU_Engine.h
new file mode 100644
index 00000000000..c34c737da2a
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/unix/GPU_Engine.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef __GPU_ENGINE_H
+#define __GPU_ENGINE_H
+
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+
+#define Object DNA_Object // tricky stuff !!! but without it it doesn't compile...
+
+#include "GPC_Engine.h"
+
+
+class GPU_Engine : public GPC_Engine
+{
+public:
+ XtIntervalId m_timerId;
+ unsigned long m_timerTimeOutMsecs;
+
+public:
+ GPU_Engine(char *customLoadingAnimation,
+ int foregroundColor, int backgroundColor, int frameRate);
+ virtual ~GPU_Engine();
+ bool Initialize(Display *display, Window window, int width, int height);
+
+ void HandleNewWindow(Window window);
+
+private:
+ void AddEventHandlers();
+};
+
+#endif // __GPU_ENGINE_H
+
diff --git a/source/gameengine/GamePlayer/common/unix/GPU_KeyboardDevice.cpp b/source/gameengine/GamePlayer/common/unix/GPU_KeyboardDevice.cpp
new file mode 100644
index 00000000000..b1b05d9a978
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/unix/GPU_KeyboardDevice.cpp
@@ -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 is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "GPU_KeyboardDevice.h"
+
+void GPU_KeyboardDevice::register_X_key_down_event(KeySym k)
+{
+ ConvertEvent(k, 1);
+}
+
+void GPU_KeyboardDevice::register_X_key_up_event(KeySym k)
+{
+ ConvertEvent(k, 0);
+}
+
+
+#define map_x_key_to_kx_key(x,y) m_reverseKeyTranslateTable[x] = y;
+
+GPU_KeyboardDevice::GPU_KeyboardDevice(void)
+{
+ unsigned int i = 0;
+
+ // Needed?
+ m_reverseKeyTranslateTable.clear();
+
+ for (i = XK_A; i< XK_Z; i++) {
+ m_reverseKeyTranslateTable[i]
+ = (SCA_IInputDevice::KX_EnumInputs)
+ (((unsigned int)SCA_IInputDevice::KX_AKEY) + i - XK_A);
+ }
+
+ // Shifted versions: should not occur: KX doesn't distinguish
+ for (i = XK_a; i< XK_z; i++) {
+ m_reverseKeyTranslateTable[i]
+ = (SCA_IInputDevice::KX_EnumInputs)
+ (((int)SCA_IInputDevice::KX_AKEY) + i - XK_a);
+ }
+
+ for (i = XK_0; i< XK_9; i++) {
+ m_reverseKeyTranslateTable[i]
+ = (SCA_IInputDevice::KX_EnumInputs)
+ (((int)SCA_IInputDevice::KX_ZEROKEY) + i - XK_0);
+ }
+
+ for (i = XK_F1; i< XK_F12; i++) {
+ m_reverseKeyTranslateTable[i]
+ = (SCA_IInputDevice::KX_EnumInputs)
+ (((int)SCA_IInputDevice::KX_F1KEY) + i - XK_F1);
+ }
+
+ // the remainder:
+ map_x_key_to_kx_key(XK_BackSpace, SCA_IInputDevice::KX_BACKSPACEKEY);
+ map_x_key_to_kx_key(XK_Tab, SCA_IInputDevice::KX_TABKEY);
+ map_x_key_to_kx_key(XK_Return, SCA_IInputDevice::KX_RETKEY);
+ map_x_key_to_kx_key(XK_Escape, SCA_IInputDevice::KX_ESCKEY);
+ map_x_key_to_kx_key(XK_space, SCA_IInputDevice::KX_SPACEKEY);
+
+ map_x_key_to_kx_key(XK_Shift_L, SCA_IInputDevice::KX_LEFTSHIFTKEY);
+ map_x_key_to_kx_key(XK_Shift_R, SCA_IInputDevice::KX_RIGHTSHIFTKEY);
+ map_x_key_to_kx_key(XK_Control_L, SCA_IInputDevice::KX_LEFTCTRLKEY);
+ map_x_key_to_kx_key(XK_Control_R, SCA_IInputDevice::KX_RIGHTCTRLKEY);
+ map_x_key_to_kx_key(XK_Alt_L, SCA_IInputDevice::KX_LEFTALTKEY);
+ map_x_key_to_kx_key(XK_Alt_R, SCA_IInputDevice::KX_RIGHTALTKEY);
+
+ map_x_key_to_kx_key(XK_Insert, SCA_IInputDevice::KX_INSERTKEY);
+ map_x_key_to_kx_key(XK_Delete, SCA_IInputDevice::KX_DELKEY);
+ map_x_key_to_kx_key(XK_Home, SCA_IInputDevice::KX_HOMEKEY);
+ map_x_key_to_kx_key(XK_End, SCA_IInputDevice::KX_ENDKEY);
+ map_x_key_to_kx_key(XK_Page_Up, SCA_IInputDevice::KX_PAGEUPKEY);
+ map_x_key_to_kx_key(XK_Page_Down, SCA_IInputDevice::KX_PAGEDOWNKEY);
+
+ map_x_key_to_kx_key(XK_Left, SCA_IInputDevice::KX_LEFTARROWKEY);
+ map_x_key_to_kx_key(XK_Right, SCA_IInputDevice::KX_RIGHTARROWKEY);
+ map_x_key_to_kx_key(XK_Up, SCA_IInputDevice::KX_UPARROWKEY);
+ map_x_key_to_kx_key(XK_Down, SCA_IInputDevice::KX_DOWNARROWKEY);
+
+ map_x_key_to_kx_key(XK_KP_0, SCA_IInputDevice::KX_PAD0);
+ map_x_key_to_kx_key(XK_KP_1, SCA_IInputDevice::KX_PAD1);
+ map_x_key_to_kx_key(XK_KP_2, SCA_IInputDevice::KX_PAD2);
+ map_x_key_to_kx_key(XK_KP_3, SCA_IInputDevice::KX_PAD3);
+ map_x_key_to_kx_key(XK_KP_4, SCA_IInputDevice::KX_PAD4);
+ map_x_key_to_kx_key(XK_KP_5, SCA_IInputDevice::KX_PAD5);
+ map_x_key_to_kx_key(XK_KP_6, SCA_IInputDevice::KX_PAD6);
+ map_x_key_to_kx_key(XK_KP_7, SCA_IInputDevice::KX_PAD7);
+ map_x_key_to_kx_key(XK_KP_8, SCA_IInputDevice::KX_PAD8);
+ map_x_key_to_kx_key(XK_KP_9, SCA_IInputDevice::KX_PAD9);
+ map_x_key_to_kx_key(XK_KP_Decimal, SCA_IInputDevice::KX_PADPERIOD);
+
+ map_x_key_to_kx_key(XK_KP_Insert, SCA_IInputDevice::KX_INSERTKEY);
+ map_x_key_to_kx_key(XK_KP_End, SCA_IInputDevice::KX_ENDKEY);
+ map_x_key_to_kx_key(XK_KP_Down, SCA_IInputDevice::KX_DOWNARROWKEY);
+ map_x_key_to_kx_key(XK_KP_Page_Down,SCA_IInputDevice::KX_PAGEDOWNKEY);
+ map_x_key_to_kx_key(XK_KP_Left, SCA_IInputDevice::KX_LEFTARROWKEY);
+ map_x_key_to_kx_key(XK_KP_Right, SCA_IInputDevice::KX_RIGHTARROWKEY);
+ map_x_key_to_kx_key(XK_KP_Home, SCA_IInputDevice::KX_HOMEKEY);
+ map_x_key_to_kx_key(XK_KP_Up, SCA_IInputDevice::KX_UPARROWKEY);
+ map_x_key_to_kx_key(XK_KP_Page_Up, SCA_IInputDevice::KX_PAGEUPKEY);
+ map_x_key_to_kx_key(XK_KP_Delete, SCA_IInputDevice::KX_DELKEY);
+
+ map_x_key_to_kx_key(XK_KP_Enter, SCA_IInputDevice::KX_PADENTER);
+ map_x_key_to_kx_key(XK_KP_Add, SCA_IInputDevice::KX_PADPLUSKEY);
+ map_x_key_to_kx_key(XK_KP_Subtract, SCA_IInputDevice::KX_PADMINUS);
+ map_x_key_to_kx_key(XK_KP_Multiply, SCA_IInputDevice::KX_PADASTERKEY);
+ map_x_key_to_kx_key(XK_KP_Divide, SCA_IInputDevice::KX_PADSLASHKEY);
+
+ map_x_key_to_kx_key(XK_Caps_Lock, SCA_IInputDevice::KX_CAPSLOCKKEY);
+
+}
diff --git a/source/gameengine/GamePlayer/common/unix/GPU_KeyboardDevice.h b/source/gameengine/GamePlayer/common/unix/GPU_KeyboardDevice.h
new file mode 100644
index 00000000000..eb1a5a11cf6
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/unix/GPU_KeyboardDevice.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef __GPU_KEYBOARDDEVICE_H
+#define __GPU_KEYBOARDDEVICE_H
+
+#include <X11/keysym.h>
+#include <X11/X.h> // Brilliant name, eh? Stupid !@#!$!@#@@% This is
+ // actually needed so as not to get name clashes between Object from
+ // blender and Object from X11... The proper include would be
+ // Intrinsic.h . Yes, we are a bunch of sado-masochists. Let's hurt
+ // ourselves!
+
+#include "GPC_KeyboardDevice.h"
+
+class GPU_KeyboardDevice : public GPC_KeyboardDevice
+{
+public:
+
+ void register_X_key_down_event(KeySym k);
+ void register_X_key_up_event(KeySym k);
+
+ GPU_KeyboardDevice(void);
+ virtual ~GPU_KeyboardDevice()
+ {
+ /* intentionally empty */
+ }
+
+ private:
+ SCA_IInputDevice::KX_EnumInputs
+ convert_x_keycode_to_kx_keycode(unsigned int key);
+};
+
+#endif // _GPU_KEYBOARDDEVICE_H
+
diff --git a/source/gameengine/GamePlayer/common/unix/GPU_PolygonMaterial.h b/source/gameengine/GamePlayer/common/unix/GPU_PolygonMaterial.h
new file mode 100644
index 00000000000..62feb394441
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/unix/GPU_PolygonMaterial.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 __GPU_POLYGONMATERIAL_H
+#define __GPU_POLYGONMATERIAL_H
+
+#include "BP_PolygonMaterial.h"
+
+class GPU_PolygonMaterial : public BP_PolygonMaterial
+{
+public:
+ GPUPolygonMaterial(const STR_String& texname, bool ba,const STR_String& matname,
+ int tile, int tileXrep, int tileYrep, int mode, int transparant,
+ int lightlayer,bool bIsTriangle,void* clientobject,void* tpage) :
+ BP_PolygonMaterial(texname, ba,matname, tile, tileXrep, tileYrep,
+ mode, transparant, lightlayer, bIsTriangle, clientobject),
+ m_tface(tpage)
+ {
+ }
+
+ virtual ~GPU_PolygonMaterial()
+ {
+ }
+};
+
+#endif // __GPU_POLYGONMATERIAL_H
+
diff --git a/source/gameengine/GamePlayer/common/unix/GPU_System.cpp b/source/gameengine/GamePlayer/common/unix/GPU_System.cpp
new file mode 100644
index 00000000000..eb2163f08bc
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/unix/GPU_System.cpp
@@ -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 <sys/time.h>
+#include "GPU_System.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+static struct timeval startTime;
+static int startTimeDone = 0;
+
+
+double GPU_System::GetTimeInSeconds()
+{
+ if(!startTimeDone)
+ {
+ gettimeofday(&startTime, NULL);
+ startTimeDone = 1;
+ }
+
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ // next '1000' are used for precision
+ long ticks = (now.tv_sec - startTime.tv_sec) * 1000 + (now.tv_usec - startTime.tv_usec) / 1000;
+ double secs = (double)ticks / 1000.0;
+ return secs;
+}
diff --git a/source/gameengine/GamePlayer/common/unix/GPU_System.h b/source/gameengine/GamePlayer/common/unix/GPU_System.h
new file mode 100644
index 00000000000..efb637dba95
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/unix/GPU_System.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 __GPU_SYSTEM_H
+#define __GPU_SYSTEM_H
+
+#include "GPC_System.h"
+
+class GPU_System : public GPC_System
+{
+public:
+ GPU_System()
+ {
+ }
+
+ virtual double GetTimeInSeconds();
+};
+
+#endif // __GPU_SYSTEM_H
+
diff --git a/source/gameengine/GamePlayer/common/unix/Makefile b/source/gameengine/GamePlayer/common/unix/Makefile
new file mode 100644
index 00000000000..9073bf02d11
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/unix/Makefile
@@ -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 *****
+#
+#
+
+LIBNAME = unix
+DIR = $(OCGDIR)/gameengine/GamePlayer/common/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_STRING)/include
+
+CPPFLAGS += -I..
+CPPFLAGS += -I../../netscape/src/ketsji
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+
+# Game Engine
+CPPFLAGS += -I../../../../gameengine/Converter
+CPPFLAGS += -I../../../../gameengine/Expressions
+CPPFLAGS += -I../../../../gameengine/GameLogic
+CPPFLAGS += -I../../../../gameengine/Ketsji
+CPPFLAGS += -I../../../../gameengine/Ketsji/KXNetwork
+CPPFLAGS += -I../../../../gameengine/Network
+CPPFLAGS += -I../../../../gameengine/Network/LoopBackNetwork
+CPPFLAGS += -I../../../../gameengine/Rasterizer
+CPPFLAGS += -I../../../../gameengine/Rasterizer/RAS_OpenGLRasterizer
+CPPFLAGS += -I../../../../gameengine/SceneGraph
+
+CPPFLAGS += -I$(NAN_FUZZICS)/include
+CPPFLAGS += -I$(NAN_SUMO)/include
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_BMFONT)/include
+CPPFLAGS += -I$(NAN_SOLID)/include
+
+# Blender stuff
+CPPFLAGS += -I../../../../blender/blenkernel
+CPPFLAGS += -I../../../../blender/blenlib
+CPPFLAGS += -I../../../../blender/blenloader
+CPPFLAGS += -I../../../../blender/imbuf
+CPPFLAGS += -I../../../../blender/makesdna
+CPPFLAGS += -I../../../../kernel/gen_system
+
+CPPFLAGS += -I../../kernel/gen_system
+
diff --git a/source/gameengine/GamePlayer/common/windows/GPW_Canvas.cpp b/source/gameengine/GamePlayer/common/windows/GPW_Canvas.cpp
new file mode 100644
index 00000000000..372ab927118
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/windows/GPW_Canvas.cpp
@@ -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 *****
+ */
+
+#include "GPW_Canvas.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+GPW_Canvas::GPW_Canvas(HWND hWnd, HDC hDC, int width, int height)
+ : GPC_Canvas(width, height), m_hWnd(hWnd), m_hRC(0), m_hDC(hDC)
+{
+}
+
+
+GPW_Canvas::~GPW_Canvas()
+{
+ if (m_hRC) {
+ ::wglDeleteContext(m_hRC);
+ }
+ //if (m_hDC) {
+ // ::ReleaseDC(m_hWnd, m_hDC);
+ //}
+}
+
+
+void GPW_Canvas::Init()
+{
+
+// log_entry("GPW_Canvas::Init");
+
+ /*
+ * Color and depth bit values are not to be trusted.
+ * For instance, on TNT2:
+ * When the screen color depth is set to 16 bit, we get 5 color bits
+ * and 16 depth bits.
+ * When the screen color depth is set to 32 bit, we get 8 color bits
+ * and 24 depth bits.
+ * Just to be safe, we request high quality settings.
+ */
+ PIXELFORMATDESCRIPTOR pfd =
+ {
+ sizeof(PIXELFORMATDESCRIPTOR), // iSize
+ 1, // iVersion
+ PFD_DRAW_TO_WINDOW |
+ PFD_SUPPORT_OPENGL |
+// PFD_STEREO |
+ PFD_DOUBLEBUFFER, // dwFlags
+ PFD_TYPE_RGBA, // iPixelType
+ 32, // cColorBits
+ 0, 0, // cRedBits, cRedShift (ignored)
+ 0, 0, // cGreenBits, cGreenShift (ignored)
+ 0, 0, // cBlueBits, cBlueShift (ignored)
+ 0, 0, // cAlphaBits, cAlphaShift (ignored)
+ 0, 0, 0, 0, 0, // cAccum_X_Bits
+ 32, // cDepthBits
+ 0, // cStencilBits
+ 0, // cAuxBuffers
+ PFD_MAIN_PLANE, // iLayerType
+ 0, // bReserved
+ 0, // dwLayerMask
+ 0, // dwVisibleMask
+ 0 // dwDamageMask
+ };
+ PIXELFORMATDESCRIPTOR match;
+
+ // Look what we get back for this pixel format
+ int pixelFormat = ::ChoosePixelFormat(m_hDC, &pfd);
+ if (!pixelFormat) {
+ DWORD error = ::GetLastError();
+ }
+ ::DescribePixelFormat(m_hDC, pixelFormat, sizeof(match), &match);
+
+ // Activate the pixel format for this context
+ ::SetPixelFormat(m_hDC, ::ChoosePixelFormat(m_hDC, &match), &match);
+
+ // Create the OpenGL context and make it current
+ m_hRC = ::wglCreateContext(m_hDC);
+ ::wglMakeCurrent(m_hDC, m_hRC);
+
+}
+
+void GPW_Canvas::SetMousePosition(int x, int y)
+{
+ POINT point = { x, y };
+ if (m_hWnd)
+ {
+ ::ClientToScreen(m_hWnd, &point);
+ ::SetCursorPos(point.x, point.y);
+ }
+}
+
+
+void GPW_Canvas::SetMouseState(RAS_MouseState mousestate)
+{
+ LPCSTR id;
+ switch (mousestate)
+ {
+ case MOUSE_INVISIBLE:
+ HideCursor();
+ break;
+ case MOUSE_WAIT:
+ ::SetCursor(::LoadCursor(0, IDC_WAIT));
+ ShowCursor();
+ break;
+ case MOUSE_NORMAL:
+ ::SetCursor(::LoadCursor(0, IDC_ARROW));
+ ShowCursor();
+ break;
+ }
+}
+
+
+bool GPW_Canvas::BeginDraw(void)
+{
+ ::wglMakeCurrent(m_hDC, m_hRC);
+ // check errors, anyone?
+ return true;
+}
+
+
+void GPW_Canvas::EndDraw(void)
+{
+ ::wglMakeCurrent(NULL, NULL);
+}
+
+void GPW_Canvas::SwapBuffers(void)
+{
+ if (m_hDC) {
+ ::SwapBuffers(m_hDC);
+ }
+}
+
+
+void GPW_Canvas::HideCursor(void)
+{
+ int count = ::ShowCursor(FALSE);
+ while (count >= 0)
+ {
+ count = ::ShowCursor(FALSE);
+ }
+}
+
+
+void GPW_Canvas::ShowCursor(void)
+{
+ ::ShowCursor(TRUE);
+}
+
diff --git a/source/gameengine/GamePlayer/common/windows/GPW_Canvas.h b/source/gameengine/GamePlayer/common/windows/GPW_Canvas.h
new file mode 100644
index 00000000000..d08ec3c4fa5
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/windows/GPW_Canvas.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 *****
+ */
+
+#ifndef _GPW_CANVAS_H_
+#define _GPW_CANVAS_H_
+
+#ifdef WIN32
+#pragma warning (disable:4786) // suppress stl-MSVC debug info warning
+#endif
+
+#include <iostream>
+#include <windows.h>
+#include <gl/gl.h>
+
+#include "GPC_Canvas.h"
+
+
+class GPW_Canvas : public GPC_Canvas
+{
+protected:
+ /** The window handle. */
+ HWND m_hWnd;
+ /** Rendering context. */
+ HGLRC m_hRC;
+ /** Device Context. */
+ HDC m_hDC;
+
+public:
+ /**
+ * Constructor.
+ */
+ GPW_Canvas(HWND hWnd, HDC hDC, int width, int height);
+
+ /**
+ * Destructor.
+ */
+ virtual ~GPW_Canvas(void);
+
+ virtual void Init(void);
+
+ /**
+ * Moves the cursor to a new location.
+ * @param x The x-coordinate of the new location.
+ * @param x The y-coordinate of the new location.
+ */
+ virtual void SetMousePosition(int x, int y);
+
+ /**
+ * Sets the cursor shape and/or visibility.
+ * @param mousestate The new state ofthe cursor.
+ */
+ virtual void SetMouseState(RAS_MouseState mousestate);
+
+ bool BeginDraw(void);
+ void EndDraw(void);
+
+ virtual void SwapBuffers(void);
+
+ virtual HDC GetHDC(void)
+ {
+ return m_hDC;
+ }
+
+ virtual void SetHDC(HDC hDC)
+ {
+ if (hDC != m_hDC) {
+ m_hDC = hDC;
+ }
+ }
+
+ virtual HGLRC GetHGLRC(void)
+ {
+ return m_hRC;
+ }
+
+protected:
+ /**
+ * Hides the mouse cursor.
+ */
+ void HideCursor(void);
+
+ /**
+ * Shows the mouse cursor.
+ */
+ void ShowCursor(void);
+};
+
+#endif // _GPW_CANVAS_H_
+
diff --git a/source/gameengine/GamePlayer/common/windows/GPW_Engine.cpp b/source/gameengine/GamePlayer/common/windows/GPW_Engine.cpp
new file mode 100644
index 00000000000..43d2ca9bb6e
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/windows/GPW_Engine.cpp
@@ -0,0 +1,123 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 (disable : 4786)
+
+#include <assert.h>
+
+#include "GPC_MouseDevice.h"
+#include "GPC_RenderTools.h"
+#include "GPC_RawImage.h"
+
+#include "GPW_Canvas.h"
+#include "GPW_Engine.h"
+#include "GPW_KeyboardDevice.h"
+#include "GPW_System.h"
+
+#include "SND_DeviceManager.h"
+
+#include "NG_NetworkScene.h"
+#include "NG_LoopBackNetworkDeviceInterface.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+GPW_Engine::GPW_Engine(char *customLoadingAnimationURL,
+ int foregroundColor, int backgroundColor, int frameRate) :
+ GPC_Engine(customLoadingAnimationURL, foregroundColor, backgroundColor,
+ frameRate)
+{
+}
+
+
+GPW_Engine::~GPW_Engine()
+{
+}
+
+
+bool GPW_Engine::Initialize(HDC hdc, int width, int height)
+{
+ SND_DeviceManager::Subscribe();
+ m_audiodevice = SND_DeviceManager::Instance();
+
+ m_keyboarddev = new GPW_KeyboardDevice();
+ m_mousedev = new GPC_MouseDevice();
+
+ // constructor only initializes data
+ m_canvas = new GPW_Canvas(0, hdc, width, height);
+ m_canvas->Init(); // create the actual visual and rendering context
+
+ // put the Blender logo in the topleft corner
+ if(m_BlenderLogo != 0)
+ // adding a banner automatically enables them
+ m_BlenderLogoId = m_canvas->AddBanner(m_BlenderLogo->Width(), m_BlenderLogo->Height(),
+ m_BlenderLogo->Width(), m_BlenderLogo->Height(),
+ m_BlenderLogo->Data(), GPC_Canvas::alignTopLeft);
+
+ // put the Blender3D logo in the bottom right corner
+ if(m_Blender3DLogo != 0)
+ // adding a banner automatically enables them
+ m_Blender3DLogoId = m_canvas->AddBanner(m_Blender3DLogo->Width(), m_Blender3DLogo->Height(),
+ m_Blender3DLogo->Width(), m_Blender3DLogo->Height(),
+ m_Blender3DLogo->Data(), GPC_Canvas::alignBottomRight);
+#if 0
+ // put the NaN logo in the bottom right corner
+ if(m_NaNLogo != 0)
+ // adding a banner automatically enables them
+ m_NaNLogoId = m_canvas->AddBanner(m_NaNLogo->Width(), m_NaNLogo->Height(),
+ m_NaNLogo->Width(), m_NaNLogo->Height(),
+ m_NaNLogo->Data(), GPC_Canvas::alignBottomRight);
+#endif
+ // enable the display of all banners
+ m_canvas->SetBannerDisplayEnabled(true);
+
+ // stuff that must be done after creation of a rendering context
+ //m_canvas->InitPostRenderingContext();
+
+ m_rendertools = new GPC_RenderTools();
+
+ m_networkdev = new NG_LoopBackNetworkDeviceInterface();
+ assert(m_networkdev);
+
+ // creation of system needs 'current rendering context', this is taken care
+ // of by the GPW_Canvas
+ m_system = new GPW_System();
+
+// m_system->SetKeyboardDevice((GPW_KeyboardDevice *)m_keyboarddev);
+// m_system->SetMouseDevice(m_mousedev);
+// m_system->SetNetworkDevice(m_networkdev);
+
+ m_initialized = true;
+
+ return m_initialized;
+}
diff --git a/source/gameengine/GamePlayer/common/windows/GPW_Engine.h b/source/gameengine/GamePlayer/common/windows/GPW_Engine.h
new file mode 100644
index 00000000000..8f357358d68
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/windows/GPW_Engine.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 *****
+ */
+
+#ifndef __GPW_ENGINE_H
+#define __GPW_ENGINE_H
+
+#include "GPC_Engine.h"
+
+class GPW_Engine : public GPC_Engine
+{
+public:
+ GPW_Engine(char *customLoadingAnimation,
+ int foregroundColor, int backgroundColor, int frameRate);
+ virtual ~GPW_Engine();
+ bool Initialize(HDC hdc, int width, int height);
+};
+
+#endif // __GPW_ENGINE_H
+
diff --git a/source/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.cpp b/source/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.cpp
new file mode 100644
index 00000000000..e9d70722336
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.cpp
@@ -0,0 +1,283 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "GPW_KeyboardDevice.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// Key code values not found in winuser.h
+#ifndef VK_MINUS
+#define VK_MINUS 0xBD
+#endif // VK_MINUS
+#ifndef VK_SEMICOLON
+#define VK_SEMICOLON 0xBA
+#endif // VK_SEMICOLON
+#ifndef VK_PERIOD
+#define VK_PERIOD 0xBE
+#endif // VK_PERIOD
+#ifndef VK_COMMA
+#define VK_COMMA 0xBC
+#endif // VK_COMMA
+#ifndef VK_QUOTE
+#define VK_QUOTE 0xDE
+#endif // VK_QUOTE
+#ifndef VK_BACK_QUOTE
+#define VK_BACK_QUOTE 0xC0
+#endif // VK_BACK_QUOTE
+#ifndef VK_SLASH
+#define VK_SLASH 0xBF
+#endif // VK_SLASH
+#ifndef VK_BACK_SLASH
+#define VK_BACK_SLASH 0xDC
+#endif // VK_BACK_SLASH
+#ifndef VK_EQUALS
+#define VK_EQUALS 0xBB
+#endif // VK_EQUALS
+#ifndef VK_OPEN_BRACKET
+#define VK_OPEN_BRACKET 0xDB
+#endif // VK_OPEN_BRACKET
+#ifndef VK_CLOSE_BRACKET
+#define VK_CLOSE_BRACKET 0xDD
+#endif // VK_CLOSE_BRACKET
+
+
+
+GPW_KeyboardDevice::GPW_KeyboardDevice(void)
+{
+ m_seperateLeftRight = false;
+ m_seperateLeftRightInitialized = false;
+
+ m_reverseKeyTranslateTable['A' ] = KX_AKEY ;
+ m_reverseKeyTranslateTable['B' ] = KX_BKEY ;
+ m_reverseKeyTranslateTable['C' ] = KX_CKEY ;
+ m_reverseKeyTranslateTable['D' ] = KX_DKEY ;
+ m_reverseKeyTranslateTable['E' ] = KX_EKEY ;
+ m_reverseKeyTranslateTable['F' ] = KX_FKEY ;
+ m_reverseKeyTranslateTable['G' ] = KX_GKEY ;
+ m_reverseKeyTranslateTable['H' ] = KX_HKEY ;
+ m_reverseKeyTranslateTable['I' ] = KX_IKEY ;
+ m_reverseKeyTranslateTable['J' ] = KX_JKEY ;
+ m_reverseKeyTranslateTable['K' ] = KX_KKEY ;
+ m_reverseKeyTranslateTable['L' ] = KX_LKEY ;
+ m_reverseKeyTranslateTable['M' ] = KX_MKEY ;
+ m_reverseKeyTranslateTable['N' ] = KX_NKEY ;
+ m_reverseKeyTranslateTable['O' ] = KX_OKEY ;
+ m_reverseKeyTranslateTable['P' ] = KX_PKEY ;
+ m_reverseKeyTranslateTable['Q' ] = KX_QKEY ;
+ m_reverseKeyTranslateTable['R' ] = KX_RKEY ;
+ m_reverseKeyTranslateTable['S' ] = KX_SKEY ;
+ m_reverseKeyTranslateTable['T' ] = KX_TKEY ;
+ m_reverseKeyTranslateTable['U' ] = KX_UKEY ;
+ m_reverseKeyTranslateTable['V' ] = KX_VKEY ;
+ m_reverseKeyTranslateTable['W' ] = KX_WKEY ;
+ m_reverseKeyTranslateTable['X' ] = KX_XKEY ;
+ m_reverseKeyTranslateTable['Y' ] = KX_YKEY ;
+ m_reverseKeyTranslateTable['Z' ] = KX_ZKEY ;
+
+ m_reverseKeyTranslateTable['0' ] = KX_ZEROKEY ;
+ m_reverseKeyTranslateTable['1' ] = KX_ONEKEY ;
+ m_reverseKeyTranslateTable['2' ] = KX_TWOKEY ;
+ m_reverseKeyTranslateTable['3' ] = KX_THREEKEY ;
+ m_reverseKeyTranslateTable['4' ] = KX_FOURKEY ;
+ m_reverseKeyTranslateTable['5' ] = KX_FIVEKEY ;
+ m_reverseKeyTranslateTable['6' ] = KX_SIXKEY ;
+ m_reverseKeyTranslateTable['7' ] = KX_SEVENKEY ;
+ m_reverseKeyTranslateTable['8' ] = KX_EIGHTKEY ;
+ m_reverseKeyTranslateTable['9' ] = KX_NINEKEY ;
+
+ // Middle keyboard area keys
+ m_reverseKeyTranslateTable[VK_PAUSE ] = KX_PAUSEKEY ;
+ m_reverseKeyTranslateTable[VK_INSERT ] = KX_INSERTKEY ;
+ m_reverseKeyTranslateTable[VK_DELETE ] = KX_DELKEY ;
+ m_reverseKeyTranslateTable[VK_HOME ] = KX_HOMEKEY ;
+ m_reverseKeyTranslateTable[VK_END ] = KX_ENDKEY ;
+ m_reverseKeyTranslateTable[VK_PRIOR ] = KX_PAGEUPKEY ;
+ m_reverseKeyTranslateTable[VK_NEXT ] = KX_PAGEDOWNKEY ;
+
+ // Arrow keys
+ m_reverseKeyTranslateTable[VK_UP ] = KX_UPARROWKEY ;
+ m_reverseKeyTranslateTable[VK_DOWN ] = KX_DOWNARROWKEY ;
+ m_reverseKeyTranslateTable[VK_LEFT ] = KX_LEFTARROWKEY ;
+ m_reverseKeyTranslateTable[VK_RIGHT ] = KX_RIGHTARROWKEY ;
+
+ // Function keys
+ m_reverseKeyTranslateTable[VK_F1 ] = KX_F1KEY ;
+ m_reverseKeyTranslateTable[VK_F2 ] = KX_F2KEY ;
+ m_reverseKeyTranslateTable[VK_F3 ] = KX_F3KEY ;
+ m_reverseKeyTranslateTable[VK_F4 ] = KX_F4KEY ;
+ m_reverseKeyTranslateTable[VK_F5 ] = KX_F5KEY ;
+ m_reverseKeyTranslateTable[VK_F6 ] = KX_F6KEY ;
+ m_reverseKeyTranslateTable[VK_F7 ] = KX_F7KEY ;
+ m_reverseKeyTranslateTable[VK_F8 ] = KX_F8KEY ;
+ m_reverseKeyTranslateTable[VK_F9 ] = KX_F9KEY ;
+ m_reverseKeyTranslateTable[VK_F10 ] = KX_F10KEY ;
+ m_reverseKeyTranslateTable[VK_F11 ] = KX_F11KEY ;
+ m_reverseKeyTranslateTable[VK_F12 ] = KX_F12KEY ;
+
+ // Numpad keys
+ m_reverseKeyTranslateTable[VK_NUMPAD0 ] = KX_PAD0 ;
+ m_reverseKeyTranslateTable[VK_NUMPAD1 ] = KX_PAD1 ;
+ m_reverseKeyTranslateTable[VK_NUMPAD2 ] = KX_PAD2 ;
+ m_reverseKeyTranslateTable[VK_NUMPAD3 ] = KX_PAD3 ;
+ m_reverseKeyTranslateTable[VK_NUMPAD4 ] = KX_PAD4 ;
+ m_reverseKeyTranslateTable[VK_NUMPAD5 ] = KX_PAD5 ;
+ m_reverseKeyTranslateTable[VK_NUMPAD6 ] = KX_PAD6 ;
+ m_reverseKeyTranslateTable[VK_NUMPAD7 ] = KX_PAD7 ;
+ m_reverseKeyTranslateTable[VK_NUMPAD8 ] = KX_PAD8 ;
+ m_reverseKeyTranslateTable[VK_NUMPAD9 ] = KX_PAD9 ;
+ m_reverseKeyTranslateTable[VK_MULTIPLY ] = KX_PADASTERKEY ;
+ m_reverseKeyTranslateTable[VK_ADD ] = KX_PADPLUSKEY ;
+ m_reverseKeyTranslateTable[VK_DECIMAL ] = KX_PADPERIOD ;
+ m_reverseKeyTranslateTable[VK_SUBTRACT ] = KX_PADMINUS ;
+ m_reverseKeyTranslateTable[VK_DIVIDE ] = KX_PADSLASHKEY ;
+ m_reverseKeyTranslateTable[VK_SEPARATOR ] = KX_PADENTER ;
+
+ // Other keys
+ m_reverseKeyTranslateTable[VK_CAPITAL ] = KX_CAPSLOCKKEY ;
+ m_reverseKeyTranslateTable[VK_ESCAPE ] = KX_ESCKEY ;
+ m_reverseKeyTranslateTable[VK_TAB ] = KX_TABKEY ;
+ //m_reverseKeyTranslateTable[VK_RETURN ] = KX_RETKEY ;
+ m_reverseKeyTranslateTable[VK_SPACE ] = KX_SPACEKEY ;
+ m_reverseKeyTranslateTable[VK_RETURN ] = KX_LINEFEEDKEY ;
+ m_reverseKeyTranslateTable[VK_BACK ] = KX_BACKSPACEKEY ;
+ m_reverseKeyTranslateTable[VK_SEMICOLON ] = KX_SEMICOLONKEY ;
+ m_reverseKeyTranslateTable[VK_PERIOD ] = KX_PERIODKEY ;
+ m_reverseKeyTranslateTable[VK_COMMA ] = KX_COMMAKEY ;
+ m_reverseKeyTranslateTable[VK_QUOTE ] = KX_QUOTEKEY ;
+ m_reverseKeyTranslateTable[VK_BACK_QUOTE ] = KX_ACCENTGRAVEKEY ;
+ m_reverseKeyTranslateTable[VK_MINUS ] = KX_MINUSKEY ;
+ m_reverseKeyTranslateTable[VK_SLASH ] = KX_SLASHKEY ;
+ m_reverseKeyTranslateTable[VK_BACK_SLASH ] = KX_BACKSLASHKEY ;
+ m_reverseKeyTranslateTable[VK_EQUALS ] = KX_EQUALKEY ;
+ m_reverseKeyTranslateTable[VK_OPEN_BRACKET ] = KX_LEFTBRACKETKEY ;
+ m_reverseKeyTranslateTable[VK_CLOSE_BRACKET ] = KX_RIGHTBRACKETKEY ;
+
+ /*
+ * Need to handle Ctrl, Alt and Shift keys differently.
+ * Win32 messages do not discriminate left and right keys.
+ */
+ m_reverseKeyTranslateTable[VK_LCONTROL ] = KX_LEFTCTRLKEY ;
+ m_reverseKeyTranslateTable[VK_RCONTROL ] = KX_RIGHTCTRLKEY ;
+ m_reverseKeyTranslateTable[VK_LMENU ] = KX_LEFTALTKEY ;
+ m_reverseKeyTranslateTable[VK_RMENU ] = KX_RIGHTALTKEY ;
+ m_reverseKeyTranslateTable[VK_RSHIFT ] = KX_RIGHTSHIFTKEY ;
+ m_reverseKeyTranslateTable[VK_LSHIFT ] = KX_LEFTSHIFTKEY ;
+}
+
+
+GPW_KeyboardDevice::~GPW_KeyboardDevice(void)
+{
+}
+
+
+void GPW_KeyboardDevice::ConvertWinEvent(WPARAM wParam, bool isDown)
+{
+ if ((wParam == VK_SHIFT) || (wParam == VK_MENU) || (wParam == VK_CONTROL)) {
+ ConvertModifierKey(wParam, isDown);
+ }
+ else {
+ ConvertEvent(wParam, isDown);
+ }
+}
+
+
+void GPW_KeyboardDevice::ConvertModifierKey(WPARAM wParam, bool isDown)
+{
+ /*
+ GetKeyState and GetAsyncKeyState only work with Win95, Win98, NT4,
+ Terminal Server and Windows 2000.
+ But on WinME it always returns zero. These two functions are simply
+ skipped by Millenium Edition!
+
+ Official explanation from Microsoft:
+ Intentionally disabled.
+ It didn't work all that well on some newer hardware, and worked less
+ well with the passage of time, so it was fully disabled in ME.
+ */
+ if (!m_seperateLeftRightInitialized && isDown) {
+ CheckForSeperateLeftRight(wParam);
+ }
+ if (m_seperateLeftRight) {
+ bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
+ ConvertEvent(VK_LSHIFT, down);
+ down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
+ ConvertEvent(VK_RSHIFT, down);
+ down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
+ ConvertEvent(VK_LMENU, down);
+ down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
+ ConvertEvent(VK_RMENU, down);
+ down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
+ ConvertEvent(VK_LCONTROL, down);
+ down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
+ ConvertEvent(VK_RCONTROL, down);
+ }
+ else {
+ bool down = HIBYTE(::GetKeyState(VK_SHIFT)) != 0;
+ ConvertEvent(VK_LSHIFT, down);
+ ConvertEvent(VK_RSHIFT, down);
+ down = HIBYTE(::GetKeyState(VK_MENU)) != 0;
+ ConvertEvent(VK_LMENU, down);
+ ConvertEvent(VK_RMENU, down);
+ down = HIBYTE(::GetKeyState(VK_CONTROL)) != 0;
+ ConvertEvent(VK_LCONTROL, down);
+ ConvertEvent(VK_RCONTROL, down);
+ }
+}
+
+
+void GPW_KeyboardDevice::CheckForSeperateLeftRight(WPARAM wParam)
+{
+ // Check whether this system supports seperate left and right keys
+ switch (wParam) {
+ case VK_SHIFT:
+ m_seperateLeftRight =
+ (HIBYTE(::GetKeyState(VK_LSHIFT)) != 0) ||
+ (HIBYTE(::GetKeyState(VK_RSHIFT)) != 0) ?
+ true : false;
+ break;
+ case VK_CONTROL:
+ m_seperateLeftRight =
+ (HIBYTE(::GetKeyState(VK_LCONTROL)) != 0) ||
+ (HIBYTE(::GetKeyState(VK_RCONTROL)) != 0) ?
+ true : false;
+ break;
+ case VK_MENU:
+ m_seperateLeftRight =
+ (HIBYTE(::GetKeyState(VK_LMENU)) != 0) ||
+ (HIBYTE(::GetKeyState(VK_RMENU)) != 0) ?
+ true : false;
+ break;
+ }
+ m_seperateLeftRightInitialized = true;
+}
diff --git a/source/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.h b/source/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.h
new file mode 100644
index 00000000000..0e683943701
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.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 _GPW_KEYBOARDDEVICE_H_
+#define _GPW_KEYBOARDDEVICE_H_
+
+#pragma warning (disable : 4786)
+
+#include <windows.h>
+#include "GPC_KeyboardDevice.h"
+
+/**
+ * Win32 implementation of GPC_KeyboardDevice.
+ * The contructor fills the keyboard code translation map.
+ * Base class GPC_KeyboardDevice does the rest.
+ * @see SCA_IInputDevice
+ */
+class GPW_KeyboardDevice : public GPC_KeyboardDevice
+{
+public:
+ GPW_KeyboardDevice(void);
+
+ virtual ~GPW_KeyboardDevice(void);
+
+ void ConvertWinEvent(WPARAM wParam, bool isDown);
+
+protected:
+
+ void ConvertModifierKey(WPARAM wParam, bool isDown);
+
+ void CheckForSeperateLeftRight(WPARAM wParam);
+
+ /** Stores the capability of this system to distinguish left and right modifier keys. */
+ bool m_seperateLeftRight;
+ /** Stores the initialization state of the member m_leftRightDistinguishable. */
+ bool m_seperateLeftRightInitialized;
+};
+
+#endif //_GPW_KEYBOARDDEVICE_H_
+
diff --git a/source/gameengine/GamePlayer/common/windows/GPW_System.cpp b/source/gameengine/GamePlayer/common/windows/GPW_System.cpp
new file mode 100644
index 00000000000..9dbd704daed
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/windows/GPW_System.cpp
@@ -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 *****
+ * Timing routine taken and modified from KX_BlenderSystem.cpp
+ */
+
+#include <windows.h>
+#include "GPW_System.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+GPW_System::GPW_System(void)
+{
+ m_freq = 0;
+ m_lastCount = 0;
+ m_lastRest = 0;
+ m_lastTime = 0;
+}
+
+
+double GPW_System::GetTimeInSeconds()
+{
+#if 0
+ double secs = ::GetTickCount();
+ secs /= 1000.;
+ return secs;
+#else
+
+ // 03/20/1999 Thomas Hieber: completely redone to get true Millisecond
+ // accuracy instead of very rough ticks. This routine will also provide
+ // correct wrap around at the end of "long"
+
+ // m_freq was set to -1, if the current Hardware does not support
+ // high resolution timers. We will use GetTickCount instead then.
+ if (m_freq < 0) {
+ return ::GetTickCount();
+ }
+
+ // m_freq is 0, the first time this function is being called.
+ if (m_freq == 0) {
+ // Try to determine the frequency of the high resulution timer
+ if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq)) {
+ // There is no such timer....
+ m_freq = -1;
+ return 0;
+ }
+ }
+
+ // Retrieve current count
+ __int64 count = 0;
+ ::QueryPerformanceCounter((LARGE_INTEGER*)&count);
+
+ // Calculate the time passed since last call, and add the rest of
+ // those tics that didn't make it into the last reported time.
+ __int64 delta = 1000*(count-m_lastCount) + m_lastRest;
+
+ m_lastTime += (long)(delta/m_freq); // Save the new value
+ m_lastRest = delta%m_freq; // Save those ticks not being counted
+ m_lastCount = count; // Save last count
+
+ // Return a high quality measurement of time
+ return m_lastTime/1000.0;
+#endif
+}
+
+
diff --git a/source/gameengine/GamePlayer/common/windows/GPW_System.h b/source/gameengine/GamePlayer/common/windows/GPW_System.h
new file mode 100644
index 00000000000..e7dbe99cd1c
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/windows/GPW_System.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 *****
+ * Timing routine taken and modified from KX_BlenderSystem.cpp
+ */
+
+#ifndef _GPW_SYSTEM_H_
+#define _GPW_SYSTEM_H_
+
+#pragma warning (disable:4786) // suppress stl-MSVC debug info warning
+
+#include "GPC_System.h"
+
+#if defined(__CYGWIN32__)
+# define __int64 long long
+#endif
+
+class GPW_System : public GPC_System
+{
+public:
+ GPW_System();
+
+ virtual double GetTimeInSeconds();
+protected:
+
+ __int64 m_freq;
+ __int64 m_lastCount;
+ __int64 m_lastRest;
+ long m_lastTime;
+
+};
+
+#endif //_GPW_SYSTEM_H_
+
diff --git a/source/gameengine/GamePlayer/common/windows/Makefile b/source/gameengine/GamePlayer/common/windows/Makefile
new file mode 100644
index 00000000000..6ad97c1677c
--- /dev/null
+++ b/source/gameengine/GamePlayer/common/windows/Makefile
@@ -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 *****
+#
+#
+# ATTENTION: this Makefile is only used for win builds!
+
+LIBNAME = windows
+DIR = $(OCGDIR)/gameengine/GamePlayer/common/$(LIBNAME)
+
+include nan_compile.mk
+
+CPPFLAGS += -I..
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+CPPFLAGS += -I$(SRCHOME)/gameengine/GameLogic
+CPPFLAGS += -I$(SRCHOME)/gameengine/Rasterizer
+CPPFLAGS += -I$(SRCHOME)/gameengine/Ketsji
+CPPFLAGS += -I$(SRCHOME)/gameengine/Network
+CPPFLAGS += -I$(SRCHOME)/gameengine/Network/LoopBackNetwork
+
+CPPFLAGS += -I$(SRCHOME)/gameengine/Physics/Sumo/Fuzzics/include
+CPPFLAGS += -I$(SRCHOME)/gameengine/Physics/Sumo/include
+
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_BMFONT)/include
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include
+
+# Blender stuff
+CPPFLAGS += -I$(SRCHOME)/blender/blenkernel
+CPPFLAGS += -I$(SRCHOME)/blender/blenlib
+CPPFLAGS += -I$(SRCHOME)/blender/blenloader
+CPPFLAGS += -I$(SRCHOME)/blender/imbuf
+CPPFLAGS += -I$(SRCHOME)/blender/makesdna
+CPPFLAGS += -I$(SRCHOME)/kernel/gen_system
+
+CPPFLAGS += -I../../kernel/gen_system
+
diff --git a/source/gameengine/GamePlayer/ghost/CMakeLists.txt b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
new file mode 100644
index 00000000000..da7abcaf0c5
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
@@ -0,0 +1,75 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if 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
+ GPG_Application.cpp
+ GPG_Canvas.cpp
+ GPG_ghost.cpp
+ GPG_KeyboardDevice.cpp
+ GPG_System.cpp
+)
+
+SET(INC
+ .
+ ../../../../intern/string
+ ../../../../intern/ghost
+ ../../../../intern/guardedalloc
+ ../../../../intern/bmfont
+ ../../../../intern/moto/include
+ ../../../../intern/SoundSystem
+ ../../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer
+ ../../../../source/kernel/gen_system
+ ../../../../source/kernel/gen_messaging
+ ../../../../source/gameengine/Converter
+ ../../../../source/blender/imbuf
+ ../../../../source/gameengine/Ketsji
+ ../../../../source/blender/blenlib
+ ../../../../source/blender/blenkernel
+ ../../../../source/blender/readblenfile
+ ../../../../source/blender
+ ../../../../source/blender/include
+ ../../../../source/blender/makesdna
+ ../../../../source/gameengine/Rasterizer
+ ../../../../source/gameengine/GameLogic
+ ../../../../source/gameengine/Expressions
+ ../../../../source/gameengine/Network
+ ../../../../source/gameengine/SceneGraph
+ ../../../../source/gameengine/Physics/common
+ ../../../../source/gameengine/Physics/Sumo
+ ../../../../source/gameengine/Physics/Sumo/Fuzzics/include
+ ../../../../source/gameengine/Network/LoopBackNetwork
+ ../../../../source/gameengine/GamePlayer/common
+ ../../../../source/blender/misc
+ ../../../../source/blender/blenloader
+ ../../../../extern/solid
+ ${PYTHON_INC}
+)
+
+BLENDERLIB_NOLIST(gp_ghost "${SRC}" "${INC}")
+#env.BlenderLib (libname='gp_ghost', sources=source_files, includes = incs, defines = [], libtype='player',priority=0, compileflags=cflags)
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
new file mode 100644
index 00000000000..0d2aa774394
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
@@ -0,0 +1,859 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * GHOST Blender Player application implementation file.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+ #pragma warning (disable:4786) // suppress stl-MSVC debug info warning
+ #include <windows.h>
+#endif
+
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif
+
+#include "GPG_Application.h"
+
+#include <iostream>
+#include <MT_assert.h>
+
+/**********************************
+ * Begin Blender include block
+ **********************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+#include "BLI_blenlib.h"
+#include "BLO_readfile.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+/**********************************
+ * End Blender include block
+ **********************************/
+
+
+#include "SYS_System.h"
+#include "KX_KetsjiEngine.h"
+
+// include files needed by "KX_BlenderSceneConverter.h"
+#include "GEN_Map.h"
+#include "SCA_IActuator.h"
+#include "RAS_MeshObject.h"
+#include "RAS_OpenGLRasterizer.h"
+#include "RAS_VAOpenGLRasterizer.h"
+#include "RAS_ListRasterizer.h"
+#include "RAS_GLExtensionManager.h"
+#include "KX_PythonInit.h"
+#include "KX_PyConstraintBinding.h"
+#include "BL_Material.h" // MAXTEX
+
+#include "KX_BlenderSceneConverter.h"
+#include "NG_LoopBackNetworkDeviceInterface.h"
+#include "SND_DeviceManager.h"
+
+#include "GPC_MouseDevice.h"
+#include "GPC_RenderTools.h"
+#include "GPG_Canvas.h"
+#include "GPG_KeyboardDevice.h"
+#include "GPG_System.h"
+
+#include "STR_String.h"
+
+#include "GHOST_ISystem.h"
+#include "GHOST_IEvent.h"
+#include "GHOST_IEventConsumer.h"
+#include "GHOST_IWindow.h"
+#include "GHOST_Rect.h"
+
+
+static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time);
+
+static GHOST_ISystem* fSystem = 0;
+static const int kTimerFreq = 10;
+
+GPG_Application::GPG_Application(GHOST_ISystem* system, struct Main* maggie, STR_String startSceneName)
+ : m_startSceneName(startSceneName),
+ m_maggie(maggie),
+ m_exitRequested(0),
+ m_system(system),
+ m_mainWindow(0),
+ m_frameTimer(0),
+ m_cursor(GHOST_kStandardCursorFirstCursor),
+ m_engineInitialized(0),
+ m_engineRunning(0),
+ m_ketsjiengine(0),
+ m_kxsystem(0),
+ m_keyboard(0),
+ m_mouse(0),
+ m_canvas(0),
+ m_rendertools(0),
+ m_rasterizer(0),
+ m_sceneconverter(0),
+ m_networkdevice(0),
+ m_audiodevice(0),
+ m_blendermat(0)
+{
+ fSystem = system;
+}
+
+
+
+GPG_Application::~GPG_Application(void)
+{
+ exitEngine();
+ fSystem->disposeWindow(m_mainWindow);
+}
+
+
+
+bool GPG_Application::SetGameEngineData(struct Main* maggie, STR_String startSceneName)
+{
+ bool result = false;
+
+ if (maggie != NULL && startSceneName != "")
+ {
+ G.scene = (Scene*)maggie->scene.first;
+ m_maggie = maggie;
+ m_startSceneName = startSceneName;
+ result = true;
+ }
+
+ return result;
+}
+
+
+#ifdef WIN32
+#define SCR_SAVE_MOUSE_MOVE_THRESHOLD 15
+
+static HWND found_ghost_window_hwnd;
+static GHOST_IWindow* ghost_window_to_find;
+static WNDPROC ghost_wnd_proc;
+static POINT scr_save_mouse_pos;
+
+static LRESULT CALLBACK screenSaverWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL close = FALSE;
+ switch (uMsg)
+ {
+ case WM_MOUSEMOVE:
+ {
+ POINT pt;
+ GetCursorPos(&pt);
+ LONG dx = scr_save_mouse_pos.x - pt.x;
+ LONG dy = scr_save_mouse_pos.y - pt.y;
+ if (abs(dx) > SCR_SAVE_MOUSE_MOVE_THRESHOLD
+ || abs(dy) > SCR_SAVE_MOUSE_MOVE_THRESHOLD)
+ {
+ close = TRUE;
+ }
+ scr_save_mouse_pos = pt;
+ break;
+ }
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_KEYDOWN:
+ close = TRUE;
+ }
+ if (close)
+ PostMessage(hwnd,WM_CLOSE,0,0);
+ return CallWindowProc(ghost_wnd_proc, hwnd, uMsg, wParam, lParam);
+}
+
+BOOL CALLBACK findGhostWindowHWNDProc(HWND hwnd, LPARAM lParam)
+{
+ GHOST_IWindow *p = (GHOST_IWindow*) GetWindowLong(hwnd, GWL_USERDATA);
+ BOOL ret = TRUE;
+ if (p == ghost_window_to_find)
+ {
+ found_ghost_window_hwnd = hwnd;
+ ret = FALSE;
+ }
+ return ret;
+}
+
+static HWND findGhostWindowHWND(GHOST_IWindow* window)
+{
+ found_ghost_window_hwnd = NULL;
+ ghost_window_to_find = window;
+ EnumWindows(findGhostWindowHWNDProc, NULL);
+ return found_ghost_window_hwnd;
+}
+
+bool GPG_Application::startScreenSaverPreview(
+ HWND parentWindow,
+ const bool stereoVisual,
+ const int stereoMode)
+{
+ bool success = false;
+
+ RECT rc;
+ if (GetWindowRect(parentWindow, &rc))
+ {
+ int windowWidth = rc.right - rc.left;
+ int windowHeight = rc.bottom - rc.top;
+ STR_String title = "";
+
+ m_mainWindow = fSystem->createWindow(title, 0, 0, windowWidth, windowHeight, GHOST_kWindowStateMinimized,
+ GHOST_kDrawingContextTypeOpenGL, stereoVisual);
+ if (!m_mainWindow) {
+ printf("error: could not create main window\n");
+ exit(-1);
+ }
+
+ HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
+ if (!ghost_hwnd) {
+ printf("error: could find main window\n");
+ exit(-1);
+ }
+
+ SetParent(ghost_hwnd, parentWindow);
+ LONG style = GetWindowLong(ghost_hwnd, GWL_STYLE);
+ LONG exstyle = GetWindowLong(ghost_hwnd, GWL_EXSTYLE);
+
+ RECT adjrc = { 0, 0, windowWidth, windowHeight };
+ AdjustWindowRectEx(&adjrc, style, FALSE, exstyle);
+
+ style = (style & (~(WS_POPUP|WS_OVERLAPPEDWINDOW|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_TILEDWINDOW ))) | WS_CHILD;
+ SetWindowLong(ghost_hwnd, GWL_STYLE, style);
+ SetWindowPos(ghost_hwnd, NULL, adjrc.left, adjrc.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);
+
+ /* Check the size of the client rectangle of the window and resize the window
+ * so that the client rectangle has the size requested.
+ */
+ m_mainWindow->setClientSize(windowWidth, windowHeight);
+
+ success = initEngine(m_mainWindow, stereoMode);
+ if (success) {
+ success = startEngine();
+ }
+
+ }
+ return success;
+}
+
+bool GPG_Application::startScreenSaverFullScreen(
+ int width,
+ int height,
+ int bpp,int frequency,
+ const bool stereoVisual,
+ const int stereoMode)
+{
+ bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode);
+ if (ret)
+ {
+ HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
+ if (ghost_hwnd != NULL)
+ {
+ GetCursorPos(&scr_save_mouse_pos);
+ ghost_wnd_proc = (WNDPROC) GetWindowLong(ghost_hwnd, GWL_WNDPROC);
+ SetWindowLong(ghost_hwnd,GWL_WNDPROC, (LONG) screenSaverWindowProc);
+ }
+ }
+ return ret;
+}
+
+#endif
+
+bool GPG_Application::startWindow(STR_String& title,
+ int windowLeft,
+ int windowTop,
+ int windowWidth,
+ int windowHeight,
+ const bool stereoVisual,
+ const int stereoMode)
+{
+ bool success;
+ // Create the main window
+ //STR_String title ("Blender Player - GHOST");
+ m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal,
+ GHOST_kDrawingContextTypeOpenGL, stereoVisual);
+ if (!m_mainWindow) {
+ printf("error: could not create main window\n");
+ exit(-1);
+ }
+
+ /* Check the size of the client rectangle of the window and resize the window
+ * so that the client rectangle has the size requested.
+ */
+ m_mainWindow->setClientSize(windowWidth, windowHeight);
+ m_mainWindow->setCursorVisibility(false);
+
+ success = initEngine(m_mainWindow, stereoMode);
+ if (success) {
+ success = startEngine();
+ }
+ return success;
+}
+
+
+
+bool GPG_Application::startFullScreen(
+ int width,
+ int height,
+ int bpp,int frequency,
+ const bool stereoVisual,
+ const int stereoMode)
+{
+ bool success;
+ // Create the main window
+ GHOST_DisplaySetting setting;
+ setting.xPixels = width;
+ setting.yPixels = height;
+ setting.bpp = bpp;
+ setting.frequency = frequency;
+
+ fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual);
+ m_mainWindow->setCursorVisibility(false);
+
+ success = initEngine(m_mainWindow, stereoMode);
+ if (success) {
+ success = startEngine();
+ }
+ return success;
+}
+
+
+
+
+bool GPG_Application::StartGameEngine(int stereoMode)
+{
+ bool success = initEngine(m_mainWindow, stereoMode);
+
+ if (success)
+ success = startEngine();
+
+ return success;
+}
+
+
+
+void GPG_Application::StopGameEngine()
+{
+ exitEngine();
+}
+
+
+
+bool GPG_Application::processEvent(GHOST_IEvent* event)
+{
+ bool handled = true;
+
+ switch (event->getType())
+ {
+ case GHOST_kEventUnknown:
+ break;
+
+ case GHOST_kEventButtonDown:
+ handled = handleButton(event, true);
+ break;
+
+ case GHOST_kEventButtonUp:
+ handled = handleButton(event, false);
+ break;
+
+ case GHOST_kEventWheel:
+ handled = handleWheel(event);
+ break;
+
+ case GHOST_kEventCursorMove:
+ handled = handleCursorMove(event);
+ break;
+
+ case GHOST_kEventKeyDown:
+ handleKey(event, true);
+ break;
+
+ case GHOST_kEventKeyUp:
+ handleKey(event, false);
+ break;
+
+
+ case GHOST_kEventWindowClose:
+ m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
+ break;
+
+ case GHOST_kEventWindowActivate:
+ handled = false;
+ break;
+ case GHOST_kEventWindowDeactivate:
+ handled = false;
+ break;
+
+ case GHOST_kEventWindowUpdate:
+ {
+ GHOST_IWindow* window = event->getWindow();
+ if (!m_system->validWindow(window)) break;
+ // Update the state of the game engine
+ if (m_kxsystem && !m_exitRequested)
+ {
+ // Proceed to next frame
+ window->activateDrawingContext();
+
+ // first check if we want to exit
+ m_exitRequested = m_ketsjiengine->GetExitCode();
+
+ // kick the engine
+ bool renderFrame = m_ketsjiengine->NextFrame();
+ if (renderFrame)
+ {
+ // render the frame
+ m_ketsjiengine->Render();
+ }
+ }
+ m_exitString = m_ketsjiengine->GetExitString();
+ }
+ break;
+
+ case GHOST_kEventWindowSize:
+ {
+ GHOST_IWindow* window = event->getWindow();
+ if (!m_system->validWindow(window)) break;
+ if (m_canvas) {
+ GHOST_Rect bnds;
+ window->getClientBounds(bnds);
+ m_canvas->Resize(bnds.getWidth(), bnds.getHeight());
+ }
+ }
+ break;
+
+ default:
+ handled = false;
+ break;
+ }
+ return handled;
+}
+
+
+
+int GPG_Application::getExitRequested(void)
+{
+ return m_exitRequested;
+}
+
+
+
+const STR_String& GPG_Application::getExitString(void)
+{
+ return m_exitString;
+}
+
+
+
+bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
+{
+ if (!m_engineInitialized)
+ {
+ bgl::InitExtensions(1);
+
+ // get and set the preferences
+ SYS_SystemHandle syshandle = SYS_GetSystem();
+ if (!syshandle)
+ return false;
+
+ // SYS_WriteCommandLineInt(syshandle, "fixedtime", 0);
+ // SYS_WriteCommandLineInt(syshandle, "vertexarrays",1);
+ bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
+ bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
+ bool fixedFr = (G.fileflags & G_FILE_ENABLE_ALL_FRAMES);
+
+ bool showPhysics = (G.fileflags & G_FILE_SHOW_PHYSICS);
+ SYS_WriteCommandLineInt(syshandle, "show_physics", showPhysics);
+
+ bool fixed_framerate= (SYS_GetCommandLineInt(syshandle, "fixed_framerate", fixedFr) != 0);
+ bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
+ bool useVertexArrays = SYS_GetCommandLineInt(syshandle,"vertexarrays",1) != 0;
+ bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", G.fileflags & G_FILE_DIAPLAY_LISTS) != 0);
+#ifdef GL_ARB_multitexture
+ int gameflag =(G.fileflags & G_FILE_GAME_MAT);
+ // ----------------------------------
+ if(bgl::RAS_EXT_support._ARB_multitexture && bgl::QueryVersion(1, 1)) {
+ m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", gameflag) != 0);
+ int unitmax=0;
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&unitmax);
+ bgl::max_texture_units = MAXTEX>unitmax?unitmax:MAXTEX;
+ //std::cout << "using(" << bgl::max_texture_units << ") of(" << unitmax << ") texture units." << std::endl;
+ } else {
+ bgl::max_texture_units = 0;
+ }
+#else
+ m_blendermat=0;
+#endif//GL_ARB_multitexture
+ // ----------------------------------
+
+ // create the canvas, rasterizer and rendertools
+ m_canvas = new GPG_Canvas(window);
+ if (!m_canvas)
+ return false;
+
+ m_canvas->Init();
+ m_rendertools = new GPC_RenderTools();
+ if (!m_rendertools)
+ goto initFailed;
+
+ if(useLists)
+ m_rasterizer = new RAS_ListRasterizer(m_canvas);
+ else if (useVertexArrays && bgl::QueryVersion(1, 1))
+ m_rasterizer = new RAS_VAOpenGLRasterizer(m_canvas);
+ else
+ m_rasterizer = new RAS_OpenGLRasterizer(m_canvas);
+ m_rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) stereoMode);
+ if (!m_rasterizer)
+ goto initFailed;
+
+ // create the inputdevices
+ m_keyboard = new GPG_KeyboardDevice();
+ if (!m_keyboard)
+ goto initFailed;
+
+ m_mouse = new GPC_MouseDevice();
+ if (!m_mouse)
+ goto initFailed;
+
+ // create a networkdevice
+ m_networkdevice = new NG_LoopBackNetworkDeviceInterface();
+ if (!m_networkdevice)
+ goto initFailed;
+
+ // get an audiodevice
+ SND_DeviceManager::Subscribe();
+ m_audiodevice = SND_DeviceManager::Instance();
+ if (!m_audiodevice)
+ goto initFailed;
+ m_audiodevice->UseCD();
+
+ // create a ketsjisystem (only needed for timing and stuff)
+ m_kxsystem = new GPG_System (m_system);
+ if (!m_kxsystem)
+ goto initFailed;
+
+ // create the ketsjiengine
+ m_ketsjiengine = new KX_KetsjiEngine(m_kxsystem);
+
+ // set the devices
+ m_ketsjiengine->SetKeyboardDevice(m_keyboard);
+ m_ketsjiengine->SetMouseDevice(m_mouse);
+ m_ketsjiengine->SetNetworkDevice(m_networkdevice);
+ m_ketsjiengine->SetCanvas(m_canvas);
+ m_ketsjiengine->SetRenderTools(m_rendertools);
+ m_ketsjiengine->SetRasterizer(m_rasterizer);
+ m_ketsjiengine->SetNetworkDevice(m_networkdevice);
+ m_ketsjiengine->SetAudioDevice(m_audiodevice);
+ m_ketsjiengine->SetTimingDisplay(frameRate, false, false);
+
+ m_ketsjiengine->SetUseFixedTime(fixed_framerate);
+ m_ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
+
+ m_engineInitialized = true;
+ }
+
+ return m_engineInitialized;
+initFailed:
+ delete m_kxsystem;
+ delete m_audiodevice;
+ delete m_networkdevice;
+ delete m_mouse;
+ delete m_keyboard;
+ delete m_rasterizer;
+ delete m_rendertools;
+ delete m_canvas;
+ m_canvas = NULL;
+ m_rendertools = NULL;
+ m_rasterizer = NULL;
+ m_keyboard = NULL;
+ m_mouse = NULL;
+ m_networkdevice = NULL;
+ m_audiodevice = NULL;
+ m_kxsystem = NULL;
+ return false;
+}
+
+
+
+bool GPG_Application::startEngine(void)
+{
+ if (m_engineRunning) {
+ return false;
+ }
+
+ // Temporary hack to disable banner display for NaN approved content.
+ /*
+ m_canvas->SetBannerDisplayEnabled(true);
+ Camera* cam;
+ cam = (Camera*)G.scene->camera->data;
+ if (cam) {
+ if (((cam->flag) & 48)==48) {
+ m_canvas->SetBannerDisplayEnabled(false);
+ }
+ }
+ else {
+ showError(CString("Camera data invalid."));
+ return false;
+ }
+ */
+
+ // create a scene converter, create and convert the stratingscene
+ m_sceneconverter = new KX_BlenderSceneConverter(m_maggie,0, m_ketsjiengine);
+ if (m_sceneconverter)
+ {
+ STR_String startscenename = m_startSceneName.Ptr();
+ m_ketsjiengine->SetSceneConverter(m_sceneconverter);
+
+ // if (always_use_expand_framing)
+ // sceneconverter->SetAlwaysUseExpandFraming(true);
+ if(m_blendermat)
+ m_sceneconverter->SetMaterials(true);
+
+ KX_Scene* startscene = new KX_Scene(m_keyboard,
+ m_mouse,
+ m_networkdevice,
+ m_audiodevice,
+ startscenename);
+
+
+ // some python things
+ PyObject* dictionaryobject = initGamePlayerPythonScripting("Ketsji", psl_Lowest);
+ m_ketsjiengine->SetPythonDictionary(dictionaryobject);
+ initRasterizer(m_rasterizer, m_canvas);
+ PyObject *gameLogic = initGameLogic(startscene);
+ initGameKeys();
+ initPythonConstraintBinding();
+
+
+
+
+
+ m_sceneconverter->ConvertScene(
+ startscenename,
+ startscene,
+ dictionaryobject,
+ m_keyboard,
+ m_rendertools,
+ m_canvas);
+ m_ketsjiengine->AddScene(startscene);
+
+ // Create a timer that is used to kick the engine
+ if (!m_frameTimer) {
+ m_frameTimer = m_system->installTimer(0, kTimerFreq, frameTimerProc, m_mainWindow);
+ }
+ m_rasterizer->Init();
+ m_ketsjiengine->StartEngine(true);
+ m_engineRunning = true;
+
+ }
+
+ if (!m_engineRunning)
+ {
+ stopEngine();
+ }
+
+ return m_engineRunning;
+}
+
+
+void GPG_Application::stopEngine()
+{
+ // when exiting the mainloop
+ exitGamePythonScripting();
+ m_ketsjiengine->StopEngine();
+ m_networkdevice->Disconnect();
+
+ if (m_sceneconverter) {
+ delete m_sceneconverter;
+ m_sceneconverter = 0;
+ }
+ if (m_system && m_frameTimer) {
+ m_system->removeTimer(m_frameTimer);
+ m_frameTimer = 0;
+ }
+ m_engineRunning = false;
+}
+
+
+void GPG_Application::exitEngine()
+{
+ if (m_ketsjiengine)
+ {
+ stopEngine();
+ delete m_ketsjiengine;
+ m_ketsjiengine = 0;
+ }
+ if (m_kxsystem)
+ {
+ delete m_kxsystem;
+ m_kxsystem = 0;
+ }
+ if (m_audiodevice)
+ {
+ SND_DeviceManager::Unsubscribe();
+ m_audiodevice = 0;
+ }
+ if (m_networkdevice)
+ {
+ delete m_networkdevice;
+ m_networkdevice = 0;
+ }
+ if (m_mouse)
+ {
+ delete m_mouse;
+ m_mouse = 0;
+ }
+ if (m_keyboard)
+ {
+ delete m_keyboard;
+ m_keyboard = 0;
+ }
+ if (m_rasterizer)
+ {
+ delete m_rasterizer;
+ m_rasterizer = 0;
+ }
+ if (m_rendertools)
+ {
+ delete m_rendertools;
+ m_rendertools = 0;
+ }
+ if (m_canvas)
+ {
+ delete m_canvas;
+ m_canvas = 0;
+ }
+
+ m_exitRequested = 0;
+ m_engineInitialized = false;
+}
+
+bool GPG_Application::handleWheel(GHOST_IEvent* event)
+{
+ bool handled = false;
+ MT_assert(event);
+ if (m_mouse)
+ {
+ GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
+ GHOST_TEventWheelData* wheelData = static_cast<GHOST_TEventWheelData*>(eventData);
+ GPC_MouseDevice::TButtonId button;
+ if (wheelData->z > 0)
+ button = GPC_MouseDevice::buttonWheelUp;
+ else
+ button = GPC_MouseDevice::buttonWheelDown;
+ m_mouse->ConvertButtonEvent(button, true);
+ handled = true;
+ }
+ return handled;
+}
+
+bool GPG_Application::handleButton(GHOST_IEvent* event, bool isDown)
+{
+ bool handled = false;
+ MT_assert(event);
+ if (m_mouse)
+ {
+ GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
+ GHOST_TEventButtonData* buttonData = static_cast<GHOST_TEventButtonData*>(eventData);
+ GPC_MouseDevice::TButtonId button;
+ switch (buttonData->button)
+ {
+ case GHOST_kButtonMaskMiddle:
+ button = GPC_MouseDevice::buttonMiddle;
+ break;
+ case GHOST_kButtonMaskRight:
+ button = GPC_MouseDevice::buttonRight;
+ break;
+ case GHOST_kButtonMaskLeft:
+ default:
+ button = GPC_MouseDevice::buttonLeft;
+ break;
+ }
+ m_mouse->ConvertButtonEvent(button, isDown);
+ handled = true;
+ }
+ return handled;
+}
+
+
+bool GPG_Application::handleCursorMove(GHOST_IEvent* event)
+{
+ bool handled = false;
+ MT_assert(event);
+ if (m_mouse && m_mainWindow)
+ {
+ GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
+ GHOST_TEventCursorData* cursorData = static_cast<GHOST_TEventCursorData*>(eventData);
+ GHOST_TInt32 x, y;
+ m_mainWindow->screenToClient(cursorData->x, cursorData->y, x, y);
+ m_mouse->ConvertMoveEvent(x, y);
+ handled = true;
+ }
+ return handled;
+}
+
+
+bool GPG_Application::handleKey(GHOST_IEvent* event, bool isDown)
+{
+ bool handled = false;
+ MT_assert(event);
+ if (m_keyboard)
+ {
+ GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
+ GHOST_TEventKeyData* keyData = static_cast<GHOST_TEventKeyData*>(eventData);
+ if (fSystem->getFullScreen()) {
+ if (keyData->key == GHOST_kKeyEsc) {
+ m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
+ }
+ }
+ m_keyboard->ConvertEvent(keyData->key, isDown);
+ handled = true;
+ }
+ return handled;
+}
+
+
+
+static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time)
+{
+ GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData();
+ if (fSystem->validWindow(window)) {
+ window->invalidate();
+ }
+}
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.h b/source/gameengine/GamePlayer/ghost/GPG_Application.h
new file mode 100644
index 00000000000..11ede4d51ca
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.h
@@ -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 *****
+ * GHOST Blender Player application declaration file.
+ */
+
+#include "GHOST_IEventConsumer.h"
+#include "STR_String.h"
+
+#ifdef WIN32
+#include <wtypes.h>
+#endif
+
+class KX_KetsjiEngine;
+class KX_ISceneConverter;
+class NG_LoopBackNetworkDeviceInterface;
+class SND_IAudioDevice;
+class RAS_IRasterizer;
+class GHOST_IEvent;
+class GHOST_ISystem;
+class GHOST_ITimerTask;
+class GHOST_IWindow;
+class GPC_MouseDevice;
+class GPC_RenderTools;
+class GPG_Canvas;
+class GPG_KeyboardDevice;
+class GPG_System;
+struct Main;
+
+class GPG_Application : public GHOST_IEventConsumer
+{
+public:
+ GPG_Application(GHOST_ISystem* system, struct Main* maggie, STR_String startSceneName);
+ ~GPG_Application(void);
+
+ bool SetGameEngineData(struct Main* maggie,STR_String startSceneName);
+ bool startWindow(STR_String& title, int windowLeft, int windowTop, int windowWidth, int windowHeight,
+ const bool stereoVisual, const int stereoMode);
+ bool startFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode);
+#ifdef WIN32
+ bool startScreenSaverFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode);
+ bool startScreenSaverPreview(HWND parentWindow, const bool stereoVisual, const int stereoMode);
+#endif
+
+ virtual bool processEvent(GHOST_IEvent* event);
+ int getExitRequested(void);
+ const STR_String& getExitString(void);
+ bool StartGameEngine(int stereoMode);
+ void StopGameEngine();
+
+protected:
+ bool handleWheel(GHOST_IEvent* event);
+ bool handleButton(GHOST_IEvent* event, bool isDown);
+ bool handleCursorMove(GHOST_IEvent* event);
+ bool handleKey(GHOST_IEvent* event, bool isDown);
+
+ /**
+ * Initializes the game engine.
+ */
+ bool initEngine(GHOST_IWindow* window, int stereoMode);
+
+ /**
+ * Starts the game engine.
+ */
+ bool startEngine(void);
+
+ /**
+ * Stop the game engine.
+ */
+ void stopEngine(void);
+
+ /**
+ * Shuts the game engine down.
+ */
+ void exitEngine(void);
+
+ /* The game data */
+ STR_String m_startSceneName;
+ struct Main* m_maggie;
+
+ /* Exit state. */
+ int m_exitRequested;
+ STR_String m_exitString;
+ /* GHOST system abstraction. */
+ GHOST_ISystem* m_system;
+ /* Main window. */
+ GHOST_IWindow* m_mainWindow;
+ /* Timer to advance frames. */
+ GHOST_ITimerTask* m_frameTimer;
+ /* The cursor shape displayed. */
+ GHOST_TStandardCursor m_cursor;
+
+ /** Engine construction state. */
+ bool m_engineInitialized;
+ /** Engine state. */
+ bool m_engineRunning;
+
+ /** the gameengine itself */
+ KX_KetsjiEngine* m_ketsjiengine;
+ /** The game engine's system abstraction. */
+ GPG_System* m_kxsystem;
+ /** The game engine's keyboard abstraction. */
+ GPG_KeyboardDevice* m_keyboard;
+ /** The game engine's mouse abstraction. */
+ GPC_MouseDevice* m_mouse;
+ /** The game engine's canvas abstraction. */
+ GPG_Canvas* m_canvas;
+ /** The game engine's platform dependent render tools. */
+ GPC_RenderTools* m_rendertools;
+ /** the rasterizer */
+ RAS_IRasterizer* m_rasterizer;
+ /** Converts Blender data files. */
+ KX_ISceneConverter* m_sceneconverter;
+ /** Network interface. */
+ NG_LoopBackNetworkDeviceInterface* m_networkdevice;
+ /** Sound device. */
+ SND_IAudioDevice* m_audiodevice;
+
+ bool m_blendermat;
+
+};
+
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp b/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp
new file mode 100644
index 00000000000..2d378473619
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp
@@ -0,0 +1,111 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "GPG_Canvas.h"
+#include <assert.h>
+#include "GHOST_ISystem.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+GPG_Canvas::GPG_Canvas(GHOST_IWindow* window)
+: GPC_Canvas(0, 0), m_window(window)
+{
+ if (m_window)
+ {
+ GHOST_Rect bnds;
+ m_window->getClientBounds(bnds);
+ this->Resize(bnds.getWidth(), bnds.getHeight());
+ }
+}
+
+
+GPG_Canvas::~GPG_Canvas(void)
+{
+}
+
+
+void GPG_Canvas::Init()
+{
+ if (m_window)
+ {
+ GHOST_TSuccess success;
+ success = m_window->setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);
+ assert(success == GHOST_kSuccess);
+ }
+}
+
+void GPG_Canvas::SetMousePosition(int x, int y)
+{
+ GHOST_ISystem* system = GHOST_ISystem::getSystem();
+ if (system && m_window)
+ {
+ GHOST_TInt32 gx = (GHOST_TInt32)x;
+ GHOST_TInt32 gy = (GHOST_TInt32)y;
+ GHOST_TInt32 cx;
+ GHOST_TInt32 cy;
+ m_window->clientToScreen(gx, gy, cx, cy);
+ system->setCursorPosition(cx, cy);
+ }
+}
+
+
+void GPG_Canvas::SetMouseState(RAS_MouseState mousestate)
+{
+ if (m_window)
+ {
+ switch (mousestate)
+ {
+ case MOUSE_INVISIBLE:
+ m_window->setCursorVisibility(false);
+ break;
+ case MOUSE_WAIT:
+ m_window->setCursorShape(GHOST_kStandardCursorWait);
+ m_window->setCursorVisibility(true);
+ break;
+ case MOUSE_NORMAL:
+ m_window->setCursorShape(GHOST_kStandardCursorRightArrow);
+ m_window->setCursorVisibility(true);
+ break;
+ }
+ }
+}
+
+
+void GPG_Canvas::SwapBuffers()
+{
+ if (m_window)
+ {
+ m_window->swapBuffers();
+ }
+}
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Canvas.h b/source/gameengine/GamePlayer/ghost/GPG_Canvas.h
new file mode 100644
index 00000000000..8da8983bf8c
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/GPG_Canvas.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 _GPG_CANVAS_H_
+#define _GPG_CANVAS_H_
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif // WIN32
+
+#include "GPC_Canvas.h"
+
+#include "GHOST_IWindow.h"
+
+
+class GPG_Canvas : public GPC_Canvas
+{
+protected:
+ /** GHOST window. */
+ GHOST_IWindow* m_window;
+
+public:
+ GPG_Canvas(GHOST_IWindow* window);
+ virtual ~GPG_Canvas(void);
+
+ virtual void Init(void);
+ virtual void SetMousePosition(int x, int y);
+ virtual void SetMouseState(RAS_MouseState mousestate);
+ virtual void SwapBuffers();
+
+ bool BeginDraw() { return true;};
+ void EndDraw() {};
+};
+
+#endif // _GPG_CANVAS_H_
+
diff --git a/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.cpp b/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.cpp
new file mode 100644
index 00000000000..0e474827ad5
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.cpp
@@ -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 *****
+ * GHOST Blender Player keyboard device implementation.
+ */
+
+#include "GPG_KeyboardDevice.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+GPG_KeyboardDevice::GPG_KeyboardDevice(void)
+{
+ m_reverseKeyTranslateTable[GHOST_kKeyA ] = KX_AKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyB ] = KX_BKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyC ] = KX_CKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyD ] = KX_DKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyE ] = KX_EKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF ] = KX_FKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyG ] = KX_GKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyH ] = KX_HKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyI ] = KX_IKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyJ ] = KX_JKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyK ] = KX_KKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyL ] = KX_LKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyM ] = KX_MKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyN ] = KX_NKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyO ] = KX_OKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyP ] = KX_PKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyQ ] = KX_QKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyR ] = KX_RKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyS ] = KX_SKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyT ] = KX_TKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyU ] = KX_UKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyV ] = KX_VKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyW ] = KX_WKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyX ] = KX_XKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyY ] = KX_YKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyZ ] = KX_ZKEY ;
+
+ m_reverseKeyTranslateTable[GHOST_kKey0 ] = KX_ZEROKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKey1 ] = KX_ONEKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKey2 ] = KX_TWOKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKey3 ] = KX_THREEKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKey4 ] = KX_FOURKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKey5 ] = KX_FIVEKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKey6 ] = KX_SIXKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKey7 ] = KX_SEVENKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKey8 ] = KX_EIGHTKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKey9 ] = KX_NINEKEY ;
+
+ // Middle keyboard area keys
+ m_reverseKeyTranslateTable[GHOST_kKeyPause ] = KX_PAUSEKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyInsert ] = KX_INSERTKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyDelete ] = KX_DELKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyHome ] = KX_HOMEKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyEnd ] = KX_ENDKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyUpPage ] = KX_PAGEUPKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyDownPage ] = KX_PAGEDOWNKEY ;
+
+ // Arrow keys
+ m_reverseKeyTranslateTable[GHOST_kKeyUpArrow ] = KX_UPARROWKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyDownArrow ] = KX_DOWNARROWKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyLeftArrow ] = KX_LEFTARROWKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyRightArrow ] = KX_RIGHTARROWKEY ;
+
+ // Function keys
+ m_reverseKeyTranslateTable[GHOST_kKeyF1 ] = KX_F1KEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF2 ] = KX_F2KEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF3 ] = KX_F3KEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF4 ] = KX_F4KEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF5 ] = KX_F5KEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF6 ] = KX_F6KEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF7 ] = KX_F7KEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF8 ] = KX_F8KEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF9 ] = KX_F9KEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF10 ] = KX_F10KEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF11 ] = KX_F11KEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyF12 ] = KX_F12KEY ;
+
+ // Numpad keys
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpad0 ] = KX_PAD0 ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpad1 ] = KX_PAD1 ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpad2 ] = KX_PAD2 ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpad3 ] = KX_PAD3 ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpad4 ] = KX_PAD4 ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpad5 ] = KX_PAD5 ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpad6 ] = KX_PAD6 ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpad7 ] = KX_PAD7 ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpad8 ] = KX_PAD8 ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpad9 ] = KX_PAD9 ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpadAsterisk ] = KX_PADASTERKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpadPlus ] = KX_PADPLUSKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpadPeriod ] = KX_PADPERIOD ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpadMinus ] = KX_PADMINUS ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpadSlash ] = KX_PADSLASHKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyNumpadEnter ] = KX_PADENTER ;
+
+ // Other keys
+ m_reverseKeyTranslateTable[GHOST_kKeyCapsLock ] = KX_CAPSLOCKKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyEsc ] = KX_ESCKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyTab ] = KX_TABKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeySpace ] = KX_SPACEKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyEnter ] = KX_RETKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyBackSpace ] = KX_BACKSPACEKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeySemicolon ] = KX_SEMICOLONKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyPeriod ] = KX_PERIODKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyComma ] = KX_COMMAKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyQuote ] = KX_QUOTEKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyAccentGrave ] = KX_ACCENTGRAVEKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyMinus ] = KX_MINUSKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeySlash ] = KX_SLASHKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyBackslash ] = KX_BACKSLASHKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyEqual ] = KX_EQUALKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyLeftBracket ] = KX_LEFTBRACKETKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyRightBracket ] = KX_RIGHTBRACKETKEY ;
+
+ // Modifier keys.
+ m_reverseKeyTranslateTable[GHOST_kKeyLeftControl ] = KX_LEFTCTRLKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyRightControl ] = KX_RIGHTCTRLKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyLeftAlt ] = KX_LEFTALTKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyRightAlt ] = KX_RIGHTALTKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyLeftShift ] = KX_LEFTSHIFTKEY ;
+ m_reverseKeyTranslateTable[GHOST_kKeyRightShift ] = KX_RIGHTSHIFTKEY ;
+}
+
+
+GPG_KeyboardDevice::~GPG_KeyboardDevice(void)
+{
+}
diff --git a/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.h b/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.h
new file mode 100644
index 00000000000..b8e578bcd8f
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.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 *****
+ * GHOST Blender Player keyboard device.
+ */
+
+#ifndef _GPG_KEYBOARDDEVICE_H_
+#define _GPG_KEYBOARDDEVICE_H_
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif // WIN32
+
+#include "GHOST_Types.h"
+#include "GPC_KeyboardDevice.h"
+
+/**
+ * GHOST implementation of GPC_KeyboardDevice.
+ * The contructor fills the keyboard code translation map.
+ * Base class GPC_KeyboardDevice does the rest.
+ * @see SCA_IInputDevice
+ */
+class GPG_KeyboardDevice : public GPC_KeyboardDevice
+{
+public:
+ GPG_KeyboardDevice(void);
+ virtual ~GPG_KeyboardDevice(void);
+};
+
+#endif //_GPG_KEYBOARDDEVICE_H_
+
diff --git a/source/gameengine/GamePlayer/ghost/GPG_System.cpp b/source/gameengine/GamePlayer/ghost/GPG_System.cpp
new file mode 100644
index 00000000000..d9f59f8b36a
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/GPG_System.cpp
@@ -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 *****
+ * Blender Player system on GHOST.
+ */
+
+#include "GPG_System.h"
+#include <assert.h>
+#include "GHOST_ISystem.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+GPG_System::GPG_System(GHOST_ISystem* system)
+: m_system(system)
+{
+ assert(m_system);
+}
+
+
+double GPG_System::GetTimeInSeconds()
+{
+ GHOST_TInt64 millis = (GHOST_TInt64)m_system->getMilliSeconds();
+ double time = (double)millis;
+ time /= 1000.;
+ return time;
+}
+
+
diff --git a/source/gameengine/GamePlayer/ghost/GPG_System.h b/source/gameengine/GamePlayer/ghost/GPG_System.h
new file mode 100644
index 00000000000..d283c683f1d
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/GPG_System.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 *****
+ * Blender Player system on GHOST.
+ */
+
+#ifndef _GPG_SYSTEM_H_
+#define _GPG_SYSTEM_H_
+
+#ifdef WIN32
+#pragma warning (disable:4786) // suppress stl-MSVC debug info warning
+#endif // WIN32
+
+#include "GPC_System.h"
+
+class GHOST_ISystem;
+
+class GPG_System : public GPC_System
+{
+ GHOST_ISystem* m_system;
+
+public:
+ GPG_System(GHOST_ISystem* system);
+
+ virtual double GetTimeInSeconds();
+};
+
+#endif // _GPG_SYSTEM_H_
+
diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
new file mode 100644
index 00000000000..23447d36401
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
@@ -0,0 +1,768 @@
+/**
+* $Id$
+*
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+* Start up of the Blender Player on GHOST.
+*/
+
+#include <iostream>
+#include <math.h>
+
+#ifdef __linux__
+#ifdef __alpha__
+#include <signal.h>
+#endif /* __alpha__ */
+#endif /* __linux__ */
+
+#ifdef __APPLE__
+// Can't use Carbon right now because of double defined type ID (In Carbon.h and DNA_ID.h, sigh)
+//#include <Carbon/Carbon.h>
+//#include <CFBundle.h>
+#endif // __APPLE__
+#include "GEN_messaging.h"
+#include "KX_KetsjiEngine.h"
+
+/**********************************
+* Begin Blender include block
+**********************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+#include "BKE_global.h"
+#include "BKE_icons.h"
+#include "BLI_blenlib.h"
+#include "DNA_scene_types.h"
+#include "BLO_readfile.h"
+#include "BLO_readblenfile.h"
+
+ int GHOST_HACK_getFirstFile(char buf[]);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+/**********************************
+* End Blender include block
+**********************************/
+
+#include "SYS_System.h"
+#include "GPG_Application.h"
+#include "GPC_PolygonMaterial.h"
+
+#include "GHOST_ISystem.h"
+#include "RAS_IRasterizer.h"
+
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+
+#ifdef WIN32
+#include <windows.h>
+#ifdef NDEBUG
+#include <wincon.h>
+#endif // NDEBUG
+#endif // WIN32
+
+const int kMinWindowWidth = 100;
+const int kMinWindowHeight = 100;
+
+char bprogname[FILE_MAXDIR+FILE_MAXFILE];
+
+#ifdef WIN32
+typedef enum
+{
+ SCREEN_SAVER_MODE_NONE = 0,
+ SCREEN_SAVER_MODE_PREVIEW,
+ SCREEN_SAVER_MODE_SAVER,
+ SCREEN_SAVER_MODE_CONFIGURATION,
+ SCREEN_SAVER_MODE_PASSWORD,
+} ScreenSaverMode;
+
+static ScreenSaverMode scr_saver_mode = SCREEN_SAVER_MODE_NONE;
+static HWND scr_saver_hwnd = NULL;
+
+static BOOL scr_saver_init(int argc, char **argv)
+{
+ scr_saver_mode = SCREEN_SAVER_MODE_NONE;
+ scr_saver_hwnd = NULL;
+ BOOL ret = FALSE;
+
+ int len = ::strlen(argv[0]);
+ if (len > 4 && !::stricmp(".scr", argv[0] + len - 4))
+ {
+ scr_saver_mode = SCREEN_SAVER_MODE_CONFIGURATION;
+ ret = TRUE;
+ if (argc >= 2)
+ {
+ if (argc >= 3)
+ {
+ scr_saver_hwnd = (HWND) ::atoi(argv[2]);
+ }
+ if (!::stricmp("/c", argv[1]))
+ {
+ scr_saver_mode = SCREEN_SAVER_MODE_CONFIGURATION;
+ if (scr_saver_hwnd == NULL)
+ scr_saver_hwnd = ::GetForegroundWindow();
+ }
+ else if (!::stricmp("/s", argv[1]))
+ {
+ scr_saver_mode = SCREEN_SAVER_MODE_SAVER;
+ }
+ else if (!::stricmp("/a", argv[1]))
+ {
+ scr_saver_mode = SCREEN_SAVER_MODE_PASSWORD;
+ }
+ else if (!::stricmp("/p", argv[1])
+ || !::stricmp("/l", argv[1]))
+ {
+ scr_saver_mode = SCREEN_SAVER_MODE_PREVIEW;
+ }
+ }
+ }
+ return ret;
+}
+
+#endif /* WIN32 */
+
+void usage(char* program)
+{
+ char * consoleoption;
+#ifdef _WIN32
+ consoleoption = "-c ";
+#else
+ consoleoption = "";
+#endif
+
+ printf("usage: %s [-w [-p l t w h]] %s[-g gamengineoptions] "
+ "[-s stereomode] filename.blend\n", program, consoleoption);
+ printf(" -h: Prints this command summary\n");
+ printf(" -w: display in a window\n");
+ printf(" -p: specify window position\n");
+ printf(" l = window left coordinate\n");
+ printf(" t = window top coordinate\n");
+ printf(" w = window width\n");
+ printf(" h = window height\n");
+ printf(" -f: start game in full screen mode\n");
+ printf(" fw = full screen mode pixel width\n");
+ printf(" fh = full screen mode pixel height\n");
+ printf(" fb = full screen mode bits per pixel\n");
+ printf(" ff = full screen mode frequency\n");
+ printf(" -s: start player in stereo\n");
+ printf(" stereomode: hwpageflip (Quad buffered shutter glasses)\n");
+ printf(" syncdoubling (Above Below)\n");
+ printf(" sidebyside (Left Right)\n");
+ printf(" anaglyph (Red-Blue glasses)\n");
+ printf(" vinterlace (Vertical interlace for autostereo display)\n");
+ printf(" depending on the type of stereo you want\n");
+#ifdef _WIN32
+ printf(" -c: keep console window open\n");
+#endif
+ printf(" -g: game engine options:\n");
+ printf(" Name Default Description\n");
+ printf(" ----------------------------------------\n");
+ printf(" fixedtime 0 Do the same timestep each frame \"Enable all frames\"\n");
+ printf(" nomipmap 0 Disable mipmaps\n");
+ printf(" show_framerate 0 Show the frame rate\n");
+ printf(" show_properties 0 Show debug properties\n");
+ printf(" show_profile 0 Show profiling information\n");
+ printf(" vertexarrays 1 Enable vertex arrays\n");
+ printf(" blender_material 0 Enable material settings\n");
+ printf("\n");
+ printf("example: %s -p 10 10 320 200 -g noaudio c:\\loadtest.blend\n", program);
+ printf("example: %s -g vertexarrays = 0 c:\\loadtest.blend\n", program);
+}
+
+char *get_filename(int argc, char **argv) {
+#ifdef __APPLE__
+/* On Mac we park the game file (called game.blend) in the application bundle.
+* The executable is located in the bundle as well.
+* Therefore, we can locate the game relative to the executable.
+ */
+ int srclen = ::strlen(argv[0]);
+ int len = 0;
+ char *filename = NULL;
+
+ if (argc > 1) {
+ if (BLI_exists(argv[argc-1])) {
+ len = ::strlen(argv[argc-1]);
+ filename = new char [len + 1];
+ ::strcpy(filename, argv[argc-1]);
+ return(filename);
+ }
+ if (::strncmp(argv[argc-1], "-psn_", 5)==0) {
+ static char firstfilebuf[512];
+ if (GHOST_HACK_getFirstFile(firstfilebuf)) {
+ len = ::strlen(firstfilebuf);
+ filename = new char [len + 1];
+ ::strcpy(filename, firstfilebuf);
+ return(filename);
+ }
+ }
+ }
+
+ srclen -= ::strlen("MacOS/blenderplayer");
+ if (srclen > 0) {
+ len = srclen + ::strlen("Resources/game.blend");
+ filename = new char [len + 1];
+ ::strcpy(filename, argv[0]);
+ ::strcpy(filename + srclen, "Resources/game.blend");
+ //::printf("looking for file: %s\n", filename);
+
+ if (BLI_exists(filename)) {
+ return (filename);
+ }
+ }
+
+ return(NULL);
+#else
+ return (argc>1)?argv[argc-1]:NULL;
+#endif // !_APPLE
+}
+
+static BlendFileData *load_game_data(char *progname, char *filename = NULL) {
+ BlendReadError error;
+ BlendFileData *bfd = NULL;
+
+ /* try to load ourself, will only work if we are a runtime */
+ if (blo_is_a_runtime(progname)) {
+ bfd= blo_read_runtime(progname, &error);
+ if (bfd) {
+ bfd->type= BLENFILETYPE_RUNTIME;
+ strcpy(bfd->main->name, progname);
+ }
+ } else {
+ bfd= BLO_read_from_file(progname, &error);
+ }
+
+ /*
+ if (bfd && bfd->type == BLENFILETYPE_BLEND) {
+ BLO_blendfiledata_free(bfd);
+ bfd = NULL;
+ error = BRE_NOT_A_PUBFILE;
+ }
+ */
+
+ if (!bfd && filename) {
+ bfd = load_game_data(filename);
+ if (!bfd) {
+ printf("Loading %s failed: %s\n", filename, BLO_bre_as_string(error));
+ }
+ }
+
+ return bfd;
+}
+
+int main(int argc, char** argv)
+{
+ int i;
+ bool error = false;
+ SYS_SystemHandle syshandle = SYS_GetSystem();
+ bool fullScreen = false;
+ bool fullScreenParFound = false;
+ bool windowParFound = false;
+ bool closeConsole = true;
+ RAS_IRasterizer::StereoMode stereomode;
+ bool stereoWindow = false;
+ bool stereoParFound = false;
+ int windowLeft = 100;
+ int windowTop = 100;
+ int windowWidth = 640;
+ int windowHeight = 480;
+ GHOST_TUns32 fullScreenWidth = 0;
+ GHOST_TUns32 fullScreenHeight= 0;
+ int fullScreenBpp = 32;
+ int fullScreenFrequency = 60;
+
+#ifdef __linux__
+#ifdef __alpha__
+ signal (SIGFPE, SIG_IGN);
+#endif /* __alpha__ */
+#endif /* __linux__ */
+ BLI_where_am_i(bprogname, argv[0]);
+
+#ifdef __APPLE__
+ // Can't use Carbon right now because of double defined type ID (In Carbon.h and DNA_ID.h, sigh)
+ /*
+ IBNibRef nibRef;
+ WindowRef window;
+ OSStatus err;
+
+ // Create a Nib reference passing the name of the nib file (without the .nib extension)
+ // CreateNibReference only searches into the application bundle.
+ err = ::CreateNibReference(CFSTR("main"), &nibRef);
+ if (err) return -1;
+
+ // Once the nib reference is created, set the menu bar. "MainMenu" is the name of the menu bar
+ // object. This name is set in InterfaceBuilder when the nib is created.
+ err = ::SetMenuBarFromNib(nibRef, CFSTR("MenuBar"));
+ if (err) return -1;
+
+ // We don't need the nib reference anymore.
+ ::DisposeNibReference(nibRef);
+ */
+#endif // __APPLE__
+
+ GEN_init_messaging_system();
+
+ // Parse command line options
+#ifndef NDEBUG
+ printf("argv[0] = '%s'\n", argv[0]);
+#endif
+
+#ifdef WIN32
+ if (scr_saver_init(argc, argv))
+ {
+ switch (scr_saver_mode)
+ {
+ case SCREEN_SAVER_MODE_CONFIGURATION:
+ MessageBox(scr_saver_hwnd, "This screen saver has no options that you can set", "Screen Saver", MB_OK);
+ break;
+ case SCREEN_SAVER_MODE_PASSWORD:
+ /* This is W95 only, which we currently do not support.
+ Fall-back to normal screen saver behaviour in that case... */
+ case SCREEN_SAVER_MODE_SAVER:
+ fullScreen = true;
+ fullScreenParFound = true;
+ break;
+
+ case SCREEN_SAVER_MODE_PREVIEW:
+ /* This will actually be handled somewhere below... */
+ break;
+ }
+ }
+#endif
+ for (i = 1; (i < argc) && !error
+#ifdef WIN32
+ && scr_saver_mode == SCREEN_SAVER_MODE_NONE
+#endif
+ ;)
+
+ {
+#ifndef NDEBUG
+ printf("argv[%d] = '%s' , %i\n", i, argv[i],argc);
+#endif
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'g':
+ // Parse game options
+ {
+ i++;
+ if (i < argc)
+ {
+ char* paramname = argv[i];
+ // Check for single value versus assignment
+ if (i+1 < argc && (*(argv[i+1]) == '='))
+ {
+ i++;
+ if (i + 1 < argc)
+ {
+ i++;
+ // Assignment
+ SYS_WriteCommandLineInt(syshandle, paramname, atoi(argv[i]));
+ SYS_WriteCommandLineFloat(syshandle, paramname, atof(argv[i]));
+ SYS_WriteCommandLineString(syshandle, paramname, argv[i]);
+#ifndef NDEBUG
+ printf("%s = '%s'\n", paramname, argv[i]);
+#endif
+ i++;
+ }
+ else
+ {
+ error = true;
+ printf("error: argument assignment %s without value.\n", paramname);
+ }
+ }
+ else
+ {
+// SYS_WriteCommandLineInt(syshandle, argv[i++], 1);
+ }
+ }
+ }
+ break;
+
+ case 'p':
+ // Parse window position and size options
+ if (argv[i][2] == 0) {
+ i++;
+ if ((i + 4) < argc)
+ {
+ windowLeft = atoi(argv[i++]);
+ windowTop = atoi(argv[i++]);
+ windowWidth = atoi(argv[i++]);
+ windowHeight = atoi(argv[i++]);
+ windowParFound = true;
+ }
+ else
+ {
+ error = true;
+ printf("error: too few options for window argument.\n");
+ }
+ } else { /* mac specific */
+
+ if (strncmp(argv[i], "-psn_", 5)==0)
+ i++; /* skip process serial number */
+ }
+ break;
+ case 'f':
+ i++;
+ fullScreen = true;
+ fullScreenParFound = true;
+ if ((i + 2) < argc && argv[i][0] != '-' && argv[i+1][0] != '-')
+ {
+ fullScreenWidth = atoi(argv[i++]);
+ fullScreenHeight = atoi(argv[i++]);
+ if ((i + 1) < argc && argv[i][0] != '-')
+ {
+ fullScreenBpp = atoi(argv[i++]);
+ if ((i + 1) < argc && argv[i][0] != '-')
+ fullScreenFrequency = atoi(argv[i++]);
+ }
+ }
+ break;
+ case 'w':
+ // Parse window position and size options
+ {
+ fullScreen = false;
+ fullScreenParFound = true;
+ i++;
+ }
+ break;
+ case 'h':
+ usage(argv[0]);
+ return 0;
+ break;
+ case 'c':
+ i++;
+ closeConsole = false;
+ break;
+ case 's': // stereo
+ i++;
+ if ((i + 1) < argc)
+ {
+ stereomode = (RAS_IRasterizer::StereoMode) atoi(argv[i]);
+ if (stereomode < RAS_IRasterizer::RAS_STEREO_NOSTEREO || stereomode >= RAS_IRasterizer::RAS_STEREO_MAXSTEREO)
+ stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
+
+ if(!strcmp(argv[i], "nostereo")) // ok, redundant but clear
+ stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
+
+ // only the hardware pageflip method needs a stereo window
+ if(!strcmp(argv[i], "hwpageflip")) {
+ stereomode = RAS_IRasterizer::RAS_STEREO_QUADBUFFERED;
+ stereoWindow = true;
+ }
+ if(!strcmp(argv[i], "syncdoubling"))
+ stereomode = RAS_IRasterizer::RAS_STEREO_ABOVEBELOW;
+
+ if(!strcmp(argv[i], "anaglyph"))
+ stereomode = RAS_IRasterizer::RAS_STEREO_ANAGLYPH;
+
+ if(!strcmp(argv[i], "sidebyside"))
+ stereomode = RAS_IRasterizer::RAS_STEREO_SIDEBYSIDE;
+
+ if(!strcmp(argv[i], "vinterlace"))
+ stereomode = RAS_IRasterizer::RAS_STEREO_VINTERLACE;
+
+#if 0
+ // future stuff
+ if(strcmp(argv[i], "stencil")
+ stereomode = RAS_STEREO_STENCIL;
+#endif
+
+ i++;
+ stereoParFound = true;
+ }
+ else
+ {
+ error = true;
+ printf("error: too few options for stereo argument.\n");
+ }
+ break;
+ default:
+ printf("Unkown argument: %s\n", argv[i++]);
+ break;
+ }
+ }
+ else
+ {
+ i++;
+ }
+ }
+
+ if ((windowWidth < kMinWindowWidth) || (windowHeight < kMinWindowHeight))
+ {
+ error = true;
+ printf("error: window size too small.\n");
+ }
+
+ if (error )
+ {
+ usage(argv[0]);
+ return 0;
+ }
+
+ if (!stereoParFound) stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
+
+#ifdef WIN32
+ if (scr_saver_mode != SCREEN_SAVER_MODE_CONFIGURATION)
+#endif
+ {
+#ifdef __APPLE__
+ //SYS_WriteCommandLineInt(syshandle, "show_framerate", 1);
+ SYS_WriteCommandLineInt(syshandle, "nomipmap", 1);
+ //fullScreen = false; // Can't use full screen
+#endif
+
+ if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0))
+ {
+ GPC_PolygonMaterial::SetMipMappingEnabled(0);
+ }
+
+ // Create the system
+ if (GHOST_ISystem::createSystem() == GHOST_kSuccess)
+ {
+ GHOST_ISystem* system = GHOST_ISystem::getSystem();
+ assertd(system);
+
+ if (!fullScreenWidth || !fullScreenHeight)
+ system->getMainDisplayDimensions(fullScreenWidth, fullScreenHeight);
+ // process first batch of events. If the user
+ // drops a file on top off the blenderplayer icon, we
+ // recieve an event with the filename
+
+ system->processEvents(0);
+
+ // this bracket is needed for app (see below) to get out
+ // of scope before GHOST_ISystem::disposeSystem() is called.
+ {
+ int exitcode = KX_EXIT_REQUEST_NO_REQUEST;
+ STR_String exitstring = "";
+ GPG_Application app(system, NULL, exitstring);
+ bool firstTimeRunning = true;
+
+ do
+ {
+ // Read the Blender file
+ char *filename = get_filename(argc, argv);
+ char *titlename;
+ char pathname[160];
+ BlendFileData *bfd;
+
+ // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file
+ if (exitcode == KX_EXIT_REQUEST_START_OTHER_GAME)
+ {
+ char basedpath[160];
+
+ // base the actuator filename with respect
+ // to the original file working directory
+ strcpy(basedpath, exitstring.Ptr());
+ BLI_convertstringcode(basedpath, pathname, 0);
+
+ bfd = load_game_data(basedpath);
+ }
+ else
+ {
+ bfd = load_game_data(argv[0], filename);
+ }
+
+ //::printf("game data loaded from %s\n", filename);
+
+ if (!bfd) {
+ usage(argv[0]);
+ error = true;
+ exitcode = KX_EXIT_REQUEST_QUIT_GAME;
+ }
+ else
+ {
+#ifdef WIN32
+#ifdef NDEBUG
+ if (closeConsole)
+ {
+ //::FreeConsole(); // Close a console window
+ }
+#endif // NDEBUG
+#endif // WIN32
+ Main *maggie = bfd->main;
+ Scene *scene = bfd->curscene;
+ strcpy (pathname, maggie->name);
+ char *startscenename = scene->id.name + 2;
+ G.fileflags = bfd->fileflags;
+
+ //Seg Fault; icon.c gIcons == 0
+ BKE_icons_init(1);
+
+ titlename = maggie->name;
+
+ // Check whether the game should be displayed full-screen
+ if ((!fullScreenParFound) && (!windowParFound))
+ {
+ // Only use file settings when command line did not override
+ if (scene->r.fullscreen) {
+ //printf("fullscreen option found in Blender file\n");
+ fullScreen = true;
+ fullScreenWidth= scene->r.xplay;
+ fullScreenHeight= scene->r.yplay;
+ fullScreenFrequency= scene->r.freqplay;
+ fullScreenBpp = scene->r.depth;
+ }
+ else
+ {
+ fullScreen = false;
+ windowWidth = scene->r.xplay;
+ windowHeight = scene->r.yplay;
+ }
+ }
+
+
+ // Check whether the game should be displayed in stereo
+ if (!stereoParFound)
+ {
+ stereomode = (RAS_IRasterizer::StereoMode) scene->r.stereomode;
+ if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
+ stereoWindow = true;
+ }
+
+ // GPG_Application app (system, maggie, startscenename);
+ app.SetGameEngineData(maggie, startscenename);
+
+ if (firstTimeRunning)
+ {
+ firstTimeRunning = false;
+
+ if (fullScreen)
+ {
+#ifdef WIN32
+ if (scr_saver_mode == SCREEN_SAVER_MODE_SAVER)
+ {
+ app.startScreenSaverFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
+ stereoWindow, stereomode);
+ }
+ else
+#endif
+ {
+ app.startFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
+ stereoWindow, stereomode);
+ }
+ }
+ else
+ {
+#ifdef __APPLE__
+ // on Mac's we'll show the executable name instead of the 'game.blend' name
+ char tempname[1024], *appstring;
+ ::strcpy(tempname, titlename);
+
+ appstring = strstr(tempname, ".app/");
+ if (appstring) {
+ appstring[2] = 0;
+ titlename = &tempname[0];
+ }
+#endif
+ // Strip the path so that we have the name of the game file
+ STR_String path = titlename;
+#ifndef WIN32
+ vector<STR_String> parts = path.Explode('/');
+#else // WIN32
+ vector<STR_String> parts = path.Explode('\\');
+#endif // WIN32
+ STR_String title;
+ if (parts.size())
+ {
+ title = parts[parts.size()-1];
+ parts = title.Explode('.');
+ if (parts.size() > 1)
+ {
+ title = parts[0];
+ }
+ }
+ else
+ {
+ title = "blenderplayer";
+ }
+#ifdef WIN32
+ if (scr_saver_mode == SCREEN_SAVER_MODE_PREVIEW)
+ {
+ app.startScreenSaverPreview(scr_saver_hwnd, stereoWindow, stereomode);
+ }
+ else
+#endif
+ {
+ app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight,
+ stereoWindow, stereomode);
+ }
+ }
+ }
+ else
+ {
+ app.StartGameEngine(stereomode);
+ exitcode = KX_EXIT_REQUEST_NO_REQUEST;
+ }
+
+ // Add the application as event consumer
+ system->addEventConsumer(&app);
+
+ // Enter main loop
+ bool run = true;
+ while (run)
+ {
+ system->processEvents(false);
+ system->dispatchEvents();
+ if ((exitcode = app.getExitRequested()))
+ {
+ run = false;
+ exitstring = app.getExitString();
+ }
+ }
+ app.StopGameEngine();
+ BLO_blendfiledata_free(bfd);
+
+#ifdef __APPLE__
+ if (filename) {
+ delete [] filename;
+ }
+#endif // __APPLE__
+ }
+ } while (exitcode == KX_EXIT_REQUEST_RESTART_GAME || exitcode == KX_EXIT_REQUEST_START_OTHER_GAME);
+ }
+
+ // Seg Fault; icon.c gIcons == 0
+ BKE_icons_free();
+
+ // Dispose the system
+ GHOST_ISystem::disposeSystem();
+ } else {
+ error = true;
+ printf("error: couldn't create a system.\n");
+ }
+ }
+
+ return error ? -1 : 0;
+}
+
+
diff --git a/source/gameengine/GamePlayer/ghost/Makefile b/source/gameengine/GamePlayer/ghost/Makefile
new file mode 100644
index 00000000000..857b274cbae
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/Makefile
@@ -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 *****
+#
+# Makefile for GHOST game player
+
+LIBNAME = ghost
+DIR = $(OCGDIR)/gameengine/GamePlayer/ghost
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+# OpenGL header files
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_BMFONT)/include
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include
+
+CPPFLAGS += -I../../GamePlayer/common
+
+# Game Engine includes
+CPPFLAGS += -I../../Converter
+CPPFLAGS += -I../../Expressions
+CPPFLAGS += -I../../GameLogic
+CPPFLAGS += -I../../Ketsji
+CPPFLAGS += -I../../Ketsji/KXNetwork
+CPPFLAGS += -I../../Network
+CPPFLAGS += -I../../Network/LoopBackNetwork
+CPPFLAGS += -I../../Rasterizer
+CPPFLAGS += -I../../Rasterizer/RAS_OpenGLRasterizer
+CPPFLAGS += -I../../SceneGraph
+
+# Sumo
+CPPFLAGS += -I$(SRCHOME)/gameengine/Physics/Sumo/include
+CPPFLAGS += -I$(SRCHOME)/gameengine/Physics/Sumo/Fuzzics/include
+
+CPPFLAGS += -I$(NAN_MOTO)/include
+
+# Blender includes
+CPPFLAGS += -I../../../blender/blenkernel
+CPPFLAGS += -I../../../blender/blenlib
+CPPFLAGS += -I../../../blender/blenloader
+CPPFLAGS += -I../../../blender/imbuf
+CPPFLAGS += -I../../../blender/makesdna
+CPPFLAGS += -I../../../blender/readblenfile
+
+# kernel? GEN? stuff
+CPPFLAGS += -I../../../kernel/gen_system
+CPPFLAGS += -I../../../kernel/gen_messaging
+
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_GHOST)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+
diff --git a/source/gameengine/GamePlayer/ghost/SConscript b/source/gameengine/GamePlayer/ghost/SConscript
new file mode 100644
index 00000000000..f76e926e6d4
--- /dev/null
+++ b/source/gameengine/GamePlayer/ghost/SConscript
@@ -0,0 +1,49 @@
+#!/usr/bin/python
+import sys
+Import ('env')
+
+source_files = ['GPG_Application.cpp',
+ 'GPG_Canvas.cpp',
+ 'GPG_ghost.cpp',
+ 'GPG_KeyboardDevice.cpp',
+ 'GPG_System.cpp']
+
+incs = ['.',
+ '#intern/string',
+ '#intern/ghost',
+ '#intern/guardedalloc',
+ '#intern/bmfont',
+ '#intern/moto/include',
+ '#intern/SoundSystem',
+ '#source/gameengine/Rasterizer/RAS_OpenGLRasterizer',
+ '#source/kernel/gen_system',
+ '#source/kernel/gen_messaging',
+ '#source/gameengine/Converter',
+ '#source/blender/imbuf',
+ '#source/gameengine/Ketsji',
+ '#source/blender/blenlib',
+ '#source/blender/blenkernel',
+ '#source/blender/readblenfile',
+ '#source/blender',
+ '#source/blender/include',
+ '#source/blender/makesdna',
+ '#source/gameengine/Rasterizer',
+ '#source/gameengine/GameLogic',
+ '#source/gameengine/Expressions',
+ '#source/gameengine/Network',
+ '#source/gameengine/SceneGraph',
+ '#source/gameengine/Physics/common',
+ '#source/gameengine/Physics/Sumo',
+ '#source/gameengine/Physics/Sumo/Fuzzics/include',
+ '#source/gameengine/Network/LoopBackNetwork',
+ '#source/gameengine/GamePlayer/common',
+ '#source/blender/misc',
+ '#source/blender/blenloader']
+
+incs += Split(env['BF_PYTHON_INC'])
+incs += Split(env['BF_SOLID_INC'])
+cflags = []
+if env['OURPLATFORM']=='win32-vc':
+ cflags = ['/GR']
+
+env.BlenderLib (libname='gp_ghost', sources=source_files, includes = incs, defines = [], libtype='player',priority=0, compileflags=cflags)
diff --git a/source/gameengine/Ketsji/BL_Material.cpp b/source/gameengine/Ketsji/BL_Material.cpp
new file mode 100644
index 00000000000..7ed2da590a9
--- /dev/null
+++ b/source/gameengine/Ketsji/BL_Material.cpp
@@ -0,0 +1,152 @@
+// ------------------------------------
+#include "BL_Material.h"
+#include "DNA_material_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+MTex* getImageFromMaterial(Material *mat, int index)
+{
+ if(!mat) return 0;
+
+ if(!(index >=0 && index < MAX_MTEX) ) return 0;
+
+ MTex *m = mat->mtex[index];
+ return m?m:0;
+}
+
+int getNumTexChannels( Material *mat )
+{
+ int count = -1;
+ if(!mat) return -1;
+
+ for(count =0; (count < 10) && mat->mtex[count] != 0; count++) {}
+ return count;
+}
+
+BL_Material::BL_Material()
+{
+ rgb[0] = 0;
+ rgb[1] = 0;
+ rgb[2] = 0;
+ rgb[3] = 0;
+ IdMode = 0;
+ ras_mode = 0;
+ tile = 0;
+ matname = "NoMaterial";
+ matcolor[0] = 0.5f;
+ matcolor[1] = 0.5f;
+ matcolor[2] = 0.5f;
+ matcolor[3] = 0.5f;
+ speccolor[0] = 1.f;
+ speccolor[1] = 1.f;
+ speccolor[2] = 1.f;
+ transp = 0;
+ hard = 50.f;
+ spec_f = 0.5f;
+ alpha = 1.f;
+ emit = 0.f;
+ mode = 0;
+ material = 0;
+ tface = 0;
+ material_index = 0;
+ amb=0.5f;
+ num_enabled = 0;
+ num_users = 1;
+ share = false;
+
+ int i;
+ for(i=0; i<4; i++)
+ {
+ uv[i] = MT_Point2(0.f,1.f);
+ uv2[i] = MT_Point2(0.f, 1.f);
+ }
+
+ for(i=0; i<MAXTEX; i++) // :(
+ {
+ mapping[i].mapping = 0;
+ mapping[i].offsets[0] = 0.f;
+ mapping[i].offsets[1] = 0.f;
+ mapping[i].offsets[2] = 0.f;
+ mapping[i].scale[0] = 1.f;
+ mapping[i].scale[1] = 1.f;
+ mapping[i].scale[2] = 1.f;
+ mapping[i].projplane[0] = PROJX;
+ mapping[i].projplane[1] = PROJY;
+ mapping[i].projplane[2] = PROJZ;
+ mapping[i].objconame = "";
+ mtexname[i] = "NULL";
+ imageId[i]="NULL";
+ flag[i] = 0;
+ texname[i] = "NULL";
+ tilexrep[i] = 1;
+ tileyrep[i] = 1;
+ color_blend[i] = 1.f;
+ blend_mode[i] = 0;
+ img[i] = 0;
+ cubemap[i] = 0;
+ }
+}
+
+void BL_Material::SetConversionRGB(unsigned int *nrgb) {
+ rgb[0]=*nrgb++;
+ rgb[1]=*nrgb++;
+ rgb[2]=*nrgb++;
+ rgb[3]=*nrgb;
+}
+
+void BL_Material::GetConversionRGB(unsigned int *nrgb) {
+ *nrgb++ = rgb[0];
+ *nrgb++ = rgb[1];
+ *nrgb++ = rgb[2];
+ *nrgb = rgb[3];
+}
+
+void BL_Material::SetConversionUV(MT_Point2 *nuv) {
+ uv[0] = *nuv++;
+ uv[1] = *nuv++;
+ uv[2] = *nuv++;
+ uv[3] = *nuv;
+}
+
+void BL_Material::GetConversionUV(MT_Point2 *nuv){
+ *nuv++ = uv[0];
+ *nuv++ = uv[1];
+ *nuv++ = uv[2];
+ *nuv = uv[3];
+}
+void BL_Material::SetConversionUV2(MT_Point2 *nuv) {
+ uv2[0] = *nuv++;
+ uv2[1] = *nuv++;
+ uv2[2] = *nuv++;
+ uv2[3] = *nuv;
+}
+
+void BL_Material::GetConversionUV2(MT_Point2 *nuv){
+ *nuv++ = uv2[0];
+ *nuv++ = uv2[1];
+ *nuv++ = uv2[2];
+ *nuv = uv2[3];
+}
+
+
+void BL_Material::SetSharedMaterial(bool v)
+{
+ if((v && num_users == -1) || num_users > 1 )
+ share = true;
+ else
+ share = false;
+}
+
+bool BL_Material::IsShared()
+{
+ return share;
+}
+
+void BL_Material::SetUsers(int num)
+{
+ num_users = num;
+}
+
diff --git a/source/gameengine/Ketsji/BL_Material.h b/source/gameengine/Ketsji/BL_Material.h
new file mode 100644
index 00000000000..8be91316237
--- /dev/null
+++ b/source/gameengine/Ketsji/BL_Material.h
@@ -0,0 +1,177 @@
+#ifndef __BL_MATERIAL_H__
+#define __BL_MATERIAL_H__
+
+#include "STR_String.h"
+#include "MT_Point2.h"
+
+// --
+struct MTex;
+struct Material;
+struct Image;
+struct MTFace;
+struct MTex;
+struct Material;
+struct EnvMap;
+// --
+
+/** max units
+ this will default to users available units
+ to build with more available, just increment this value
+ although the more you add the slower the search time will be.
+ we will go for three, which should be enough
+*/
+#define MAXTEX 3//match in RAS_TexVert & RAS_OpenGLRasterizer
+
+// different mapping modes
+class BL_Mapping
+{
+public:
+ int mapping;
+ float scale[3];
+ float offsets[3];
+ int projplane[3];
+ STR_String objconame;
+ STR_String uvCoName;
+};
+
+// base material struct
+class BL_Material
+{
+private:
+ int num_users;
+ bool share;
+
+public:
+ // -----------------------------------
+ BL_Material();
+
+ int IdMode;
+ unsigned int ras_mode;
+
+ STR_String texname[MAXTEX];
+ unsigned int flag[MAXTEX];
+ int tile,tilexrep[MAXTEX],tileyrep[MAXTEX];
+ STR_String matname;
+ STR_String mtexname[MAXTEX];
+
+ float matcolor[4];
+ float speccolor[3];
+ short transp, pad;
+
+ float hard, spec_f;
+ float alpha, emit, color_blend[MAXTEX], ref;
+ float amb;
+
+ int blend_mode[MAXTEX];
+
+ int mode;
+ int num_enabled;
+
+ int material_index;
+
+ BL_Mapping mapping[MAXTEX];
+ STR_String imageId[MAXTEX];
+
+
+ Material* material;
+ MTFace* tface;
+ Image* img[MAXTEX];
+ EnvMap* cubemap[MAXTEX];
+
+ unsigned int rgb[4];
+ MT_Point2 uv[4];
+ MT_Point2 uv2[4];
+
+ void SetConversionRGB(unsigned int *rgb);
+ void GetConversionRGB(unsigned int *rgb);
+
+ void SetConversionUV(MT_Point2 *uv);
+ void GetConversionUV(MT_Point2 *uv);
+
+ void SetConversionUV2(MT_Point2 *uv);
+ void GetConversionUV2(MT_Point2 *uv);
+
+ void SetSharedMaterial(bool v);
+ bool IsShared();
+ void SetUsers(int num);
+};
+
+// BL_Material::IdMode
+enum BL_IdMode {
+ DEFAULT_BLENDER=-1,
+ TEXFACE,
+ ONETEX,
+ TWOTEX,
+ GREATERTHAN2
+};
+
+// BL_Material::blend_mode[index]
+enum BL_BlendMode
+{
+ BLEND_MIX=1,
+ BLEND_ADD,
+ BLEND_SUB,
+ BLEND_MUL,
+ BLEND_SCR
+};
+
+// -------------------------------------
+// BL_Material::flag[index]
+enum BL_flag
+{
+ MIPMAP=1, // set to use mipmaps
+ CALCALPHA=2, // additive
+ USEALPHA=4, // use actual alpha channel
+ TEXALPHA=8, // use alpha combiner functions
+ TEXNEG=16, // negate blending
+ HASIPO=32,
+ USENEGALPHA=64,
+ ALPHA_TEST=128
+};
+
+// BL_Material::ras_mode
+enum BL_ras_mode
+{
+ POLY_VIS=1,
+ COLLIDER=2,
+ ZSORT=4,
+ TRANSP=8,
+ TRIANGLE=16,
+ USE_LIGHT=32,
+ WIRE=64
+};
+
+// -------------------------------------
+// BL_Material::mapping[index]::mapping
+enum BL_MappingFlag
+{
+ USEENV =1,
+ // --
+ USEREFL =2,
+ USEOBJ =4,
+ USENORM =8,
+ USEORCO =16,
+ USEUV =32,
+ USETANG =64,
+ DISABLE =128,
+ USECUSTOMUV=256
+};
+
+// BL_Material::BL_Mapping::projplane
+enum BL_MappingProj
+{
+ PROJN=0,
+ PROJX,
+ PROJY,
+ PROJZ
+};
+
+// ------------------------------------
+//extern void initBL_Material(BL_Material* mat);
+extern MTex* getImageFromMaterial(Material *mat, int index);
+extern int getNumTexChannels( Material *mat );
+// ------------------------------------
+
+#endif
+
+
diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp
new file mode 100644
index 00000000000..ab0479eb88b
--- /dev/null
+++ b/source/gameengine/Ketsji/BL_Shader.cpp
@@ -0,0 +1,1470 @@
+
+
+#ifdef WIN32
+#include <windows.h>
+#endif // WIN32
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif
+
+#include <iostream>
+#include "BL_Shader.h"
+#include "BL_Material.h"
+
+#include "MT_assert.h"
+#include "MT_Matrix4x4.h"
+#include "MT_Matrix3x3.h"
+#include "KX_PyMath.h"
+#include "MEM_guardedalloc.h"
+
+#include "RAS_GLExtensionManager.h"
+#include "RAS_MeshObject.h"
+#include "RAS_IRasterizer.h"
+
+//using namespace bgl;
+#define spit(x) std::cout << x << std::endl;
+
+#define SORT_UNIFORMS 1
+#define UNIFORM_MAX_LEN sizeof(float)*16
+#define MAX_LOG_LEN 262144 // bounds
+
+BL_Uniform::BL_Uniform(int data_size)
+: mLoc(-1),
+ mDirty(true),
+ mType(UNI_NONE),
+ mTranspose(0),
+ mDataLen(data_size)
+{
+#ifdef SORT_UNIFORMS
+ MT_assert(mDataLen <= UNIFORM_MAX_LEN);
+ mData = (void*)MEM_mallocN(mDataLen, "shader-uniform-alloc");
+#endif
+}
+
+BL_Uniform::~BL_Uniform()
+{
+#ifdef SORT_UNIFORMS
+ if(mData) {
+ MEM_freeN(mData);
+ mData=0;
+ }
+#endif
+}
+
+void BL_Uniform::Apply(class BL_Shader *shader)
+{
+#ifdef GL_ARB_shader_objects
+#ifdef SORT_UNIFORMS
+ MT_assert(mType > UNI_NONE && mType < UNI_MAX && mData);
+
+ if(!mDirty)
+ return;
+
+ switch(mType)
+ {
+ case UNI_FLOAT: {
+ float *f = (float*)mData;
+ bgl::blUniform1fARB(mLoc,(GLfloat)*f);
+ }break;
+ case UNI_INT: {
+ int *f = (int*)mData;
+ bgl::blUniform1iARB(mLoc, (GLint)*f);
+ }break;
+ case UNI_FLOAT2: {
+ float *f = (float*)mData;
+ bgl::blUniform2fvARB(mLoc,1, (GLfloat*)f);
+ }break;
+ case UNI_FLOAT3: {
+ float *f = (float*)mData;
+ bgl::blUniform3fvARB(mLoc,1,(GLfloat*)f);
+ }break;
+ case UNI_FLOAT4: {
+ float *f = (float*)mData;
+ bgl::blUniform4fvARB(mLoc,1,(GLfloat*)f);
+ }break;
+ case UNI_INT2: {
+ int *f = (int*)mData;
+ bgl::blUniform2ivARB(mLoc,1,(GLint*)f);
+ }break;
+ case UNI_INT3: {
+ int *f = (int*)mData;
+ bgl::blUniform3ivARB(mLoc,1,(GLint*)f);
+ }break;
+ case UNI_INT4: {
+ int *f = (int*)mData;
+ bgl::blUniform4ivARB(mLoc,1,(GLint*)f);
+ }break;
+ case UNI_MAT4: {
+ float *f = (float*)mData;
+ bgl::blUniformMatrix4fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f);
+ }break;
+ case UNI_MAT3: {
+ float *f = (float*)mData;
+ bgl::blUniformMatrix3fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f);
+ }break;
+ }
+ mDirty = false;
+#endif
+#endif
+}
+
+void BL_Uniform::SetData(int location, int type,bool transpose)
+{
+#ifdef SORT_UNIFORMS
+ mType = type;
+ mLoc = location;
+ mDirty = true;
+#endif
+}
+
+const bool BL_Shader::Ok()const
+{
+ return (mShader !=0 && mOk && mUse);
+}
+
+BL_Shader::BL_Shader(PyTypeObject *T)
+: PyObjectPlus(T),
+ mShader(0),
+ mPass(1),
+ mOk(0),
+ mUse(0),
+ mAttr(0),
+ vertProg(""),
+ fragProg(""),
+ mError(0),
+ mDirty(true)
+{
+ // if !RAS_EXT_support._ARB_shader_objects this class will not be used
+ //for (int i=0; i<MAXTEX; i++) {
+ // mSampler[i] = BL_Sampler();
+ //}
+}
+
+using namespace bgl;
+
+BL_Shader::~BL_Shader()
+{
+#ifdef GL_ARB_shader_objects
+ //for (int i=0; i<MAXTEX; i++){
+ // if(mSampler[i].mOwn) {
+ // if(mSampler[i].mTexture)
+ // mSampler[i].mTexture->DeleteTex();
+ // }
+ //}
+ ClearUniforms();
+
+ if( mShader ) {
+ bgl::blDeleteObjectARB(mShader);
+ mShader = 0;
+ }
+ vertProg = 0;
+ fragProg = 0;
+ mOk = 0;
+ bgl::blUseProgramObjectARB(0);
+#endif//GL_ARB_shader_objects
+}
+
+void BL_Shader::ClearUniforms()
+{
+ BL_UniformVec::iterator it = mUniforms.begin();
+ while(it != mUniforms.end()){
+ delete (*it);
+ it++;
+ }
+ mUniforms.clear();
+
+
+ BL_UniformVecDef::iterator itp = mPreDef.begin();
+ while(itp != mPreDef.end()) {
+ delete (*itp);
+ itp++;
+ }
+ mPreDef.clear();
+
+}
+
+
+BL_Uniform *BL_Shader::FindUniform(const int location)
+{
+#ifdef SORT_UNIFORMS
+ BL_UniformVec::iterator it = mUniforms.begin();
+ while(it != mUniforms.end()) {
+ if((*it)->GetLocation() == location)
+ return (*it);
+ it++;
+ }
+#endif
+ return 0;
+}
+
+void BL_Shader::SetUniformfv(int location, int type, float *param,int size, bool transpose)
+{
+#ifdef SORT_UNIFORMS
+ BL_Uniform *uni= FindUniform(location);
+ if(uni) {
+ memcpy(uni->getData(), param, size);
+ uni->SetData(location, type, transpose);
+ }
+ else {
+ uni = new BL_Uniform(size);
+ memcpy(uni->getData(), param, size);
+
+ uni->SetData(location, type, transpose);
+ mUniforms.push_back(uni);
+ }
+ mDirty = true;
+#endif
+}
+
+void BL_Shader::SetUniformiv(int location, int type, int *param,int size, bool transpose)
+{
+#ifdef SORT_UNIFORMS
+ BL_Uniform *uni= FindUniform(location);
+ if(uni) {
+ memcpy(uni->getData(), param, size);
+ uni->SetData(location, type, transpose);
+ }
+ else {
+ uni = new BL_Uniform(size);
+ memcpy(uni->getData(), param, size);
+ uni->SetData(location, type, transpose);
+ mUniforms.push_back(uni);
+ }
+ mDirty = true;
+#endif
+}
+
+
+void BL_Shader::ApplyShader()
+{
+#ifdef SORT_UNIFORMS
+ if(!mDirty)
+ return;
+
+ for(unsigned int i=0; i<mUniforms.size(); i++)
+ mUniforms[i]->Apply(this);
+
+ mDirty = false;
+#endif
+}
+
+void BL_Shader::UnloadShader()
+{
+ //
+}
+
+
+bool BL_Shader::LinkProgram()
+{
+#ifdef GL_ARB_shader_objects
+
+ int vertlen = 0, fraglen=0, proglen=0;
+ int vertstatus=0, fragstatus=0, progstatus=0;
+ unsigned int tmpVert=0, tmpFrag=0, tmpProg=0;
+ int char_len=0;
+ char *logInf =0;
+
+ if(mError)
+ goto programError;
+
+ if(!vertProg || !fragProg){
+ spit("Invalid GLSL sources");
+ return false;
+ }
+ if( !RAS_EXT_support._ARB_fragment_shader) {
+ spit("Fragment shaders not supported");
+ return false;
+ }
+ if( !RAS_EXT_support._ARB_vertex_shader) {
+ spit("Vertex shaders not supported");
+ return false;
+ }
+
+ // -- vertex shader ------------------
+ tmpVert = bgl::blCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+ bgl::blShaderSourceARB(tmpVert, 1, (const char**)&vertProg, 0);
+ bgl::blCompileShaderARB(tmpVert);
+ bgl::blGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB,(GLint*) &vertlen);
+
+ // print info if any
+ if( vertlen > 0 && vertlen < MAX_LOG_LEN){
+ logInf = (char*)MEM_mallocN(vertlen, "vert-log");
+ bgl::blGetInfoLogARB(tmpVert, vertlen, (GLsizei*)&char_len, logInf);
+ if(char_len >0) {
+ spit("---- Vertex Shader Error ----");
+ spit(logInf);
+ }
+ MEM_freeN(logInf);
+ logInf=0;
+ }
+ // check for compile errors
+ bgl::blGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB,(GLint*)&vertstatus);
+ if(!vertstatus) {
+ spit("---- Vertex shader failed to compile ----");
+ goto programError;
+ }
+
+ // -- fragment shader ----------------
+ tmpFrag = bgl::blCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+ bgl::blShaderSourceARB(tmpFrag, 1,(const char**)&fragProg, 0);
+ bgl::blCompileShaderARB(tmpFrag);
+ bgl::blGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &fraglen);
+ if(fraglen >0 && fraglen < MAX_LOG_LEN){
+ logInf = (char*)MEM_mallocN(fraglen, "frag-log");
+ bgl::blGetInfoLogARB(tmpFrag, fraglen,(GLsizei*) &char_len, logInf);
+ if(char_len >0) {
+ spit("---- Fragment Shader Error ----");
+ spit(logInf);
+ }
+ MEM_freeN(logInf);
+ logInf=0;
+ }
+
+ bgl::blGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*) &fragstatus);
+ if(!fragstatus){
+ spit("---- Fragment shader failed to compile ----");
+ goto programError;
+ }
+
+
+ // -- program ------------------------
+ // set compiled vert/frag shader & link
+ tmpProg = bgl::blCreateProgramObjectARB();
+ bgl::blAttachObjectARB(tmpProg, tmpVert);
+ bgl::blAttachObjectARB(tmpProg, tmpFrag);
+ bgl::blLinkProgramARB(tmpProg);
+ bgl::blGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &proglen);
+ bgl::blGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint*) &progstatus);
+
+
+ if(proglen > 0 && proglen < MAX_LOG_LEN) {
+ logInf = (char*)MEM_mallocN(proglen, "prog-log");
+ bgl::blGetInfoLogARB(tmpProg, proglen, (GLsizei*)&char_len, logInf);
+ if(char_len >0) {
+ spit("---- GLSL Program ----");
+ spit(logInf);
+ }
+ MEM_freeN(logInf);
+ logInf=0;
+ }
+
+ if(!progstatus){
+ spit("---- GLSL program failed to link ----");
+ goto programError;
+ }
+
+ // set
+ mShader = tmpProg;
+ bgl::blDeleteObjectARB(tmpVert);
+ bgl::blDeleteObjectARB(tmpFrag);
+ mOk = 1;
+ mError = 0;
+ return true;
+
+programError:
+ if(tmpVert) {
+ bgl::blDeleteObjectARB(tmpVert);
+ tmpVert=0;
+ }
+ if(tmpFrag) {
+ bgl::blDeleteObjectARB(tmpFrag);
+ tmpFrag=0;
+ }
+
+ if(tmpProg) {
+ bgl::blDeleteObjectARB(tmpProg);
+ tmpProg=0;
+ }
+
+ mOk = 0;
+ mUse = 0;
+ mError = 1;
+ return false;
+#else
+ return false;
+#endif//GL_ARB_shader_objects
+}
+
+const char *BL_Shader::GetVertPtr()
+{
+ return vertProg?vertProg:0;
+}
+
+const char *BL_Shader::GetFragPtr()
+{
+ return fragProg?fragProg:0;
+}
+
+void BL_Shader::SetVertPtr( char *vert )
+{
+ vertProg = vert;
+}
+
+void BL_Shader::SetFragPtr( char *frag )
+{
+ fragProg = frag;
+}
+
+unsigned int BL_Shader::GetProg()
+{
+ return mShader;
+}
+//
+//const BL_Sampler* BL_Shader::GetSampler(int i)
+//{
+// MT_assert(i<=MAXTEX);
+// return &mSampler[i];
+//}
+
+void BL_Shader::SetSampler(int loc, int unit)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ bgl::blUniform1iARB(loc, unit);
+ }
+#endif
+}
+//
+//void BL_Shader::InitializeSampler(int unit, BL_Texture* texture)
+//{
+// MT_assert(unit<=MAXTEX);
+// mSampler[unit].mTexture = texture;
+// mSampler[unit].mLoc =-1;
+// mSampler[unit].mOwn = 0;
+//}
+
+void BL_Shader::SetProg(bool enable)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ if( mShader != 0 && mOk && enable) {
+ bgl::blUseProgramObjectARB(mShader);
+ }
+ else {
+ bgl::blUseProgramObjectARB(0);
+ }
+ }
+#endif
+}
+
+void BL_Shader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty )
+{
+#ifdef GL_ARB_shader_objects
+ if(!Ok() || !mPreDef.size())
+ return;
+
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ MT_Matrix4x4 model;
+ model.setValue(ms.m_OpenGLMatrix);
+ MT_Matrix4x4 view;
+ rasty->GetViewMatrix(view);
+
+ if(mAttr==SHD_TANGENT)
+ ms.m_mesh->SetMeshModified(true);
+
+ BL_UniformVecDef::iterator it;
+ for(it = mPreDef.begin(); it!= mPreDef.end(); it++)
+ {
+ BL_DefUniform *uni = (*it);
+ if(uni->mLoc == -1) continue;
+
+ switch (uni->mType)
+ {
+ case MODELMATRIX:
+ {
+ SetUniform(uni->mLoc, model);
+ break;
+ }
+ case MODELMATRIX_TRANSPOSE:
+ {
+ SetUniform(uni->mLoc, model, true);
+ break;
+ }
+ case MODELMATRIX_INVERSE:
+ {
+ model.invert();
+ SetUniform(uni->mLoc, model);
+ break;
+ }
+ case MODELMATRIX_INVERSETRANSPOSE:
+ {
+ model.invert();
+ SetUniform(uni->mLoc, model, true);
+ break;
+ }
+ case MODELVIEWMATRIX:
+ {
+ SetUniform(uni->mLoc, view*model);
+ break;
+ }
+
+ case MODELVIEWMATRIX_TRANSPOSE:
+ {
+ MT_Matrix4x4 mat(view*model);
+ SetUniform(uni->mLoc, mat, true);
+ break;
+ }
+ case MODELVIEWMATRIX_INVERSE:
+ {
+ MT_Matrix4x4 mat(view*model);
+ mat.invert();
+ SetUniform(uni->mLoc, mat);
+ break;
+ }
+ case MODELVIEWMATRIX_INVERSETRANSPOSE:
+ {
+ MT_Matrix4x4 mat(view*model);
+ mat.invert();
+ SetUniform(uni->mLoc, mat, true);
+ break;
+ }
+ case CAM_POS:
+ {
+ MT_Point3 pos(rasty->GetCameraPosition());
+ SetUniform(uni->mLoc, pos);
+ break;
+ }
+ case VIEWMATRIX:
+ {
+ SetUniform(uni->mLoc, view);
+ break;
+ }
+ case VIEWMATRIX_TRANSPOSE:
+ {
+ SetUniform(uni->mLoc, view, true);
+ break;
+ }
+ case VIEWMATRIX_INVERSE:
+ {
+ view.invert();
+ SetUniform(uni->mLoc, view);
+ break;
+ }
+ case VIEWMATRIX_INVERSETRANSPOSE:
+ {
+ view.invert();
+ SetUniform(uni->mLoc, view, true);
+ break;
+ }
+ case CONSTANT_TIMER:
+ {
+ SetUniform(uni->mLoc, (float)rasty->GetTime());
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+#endif
+}
+
+
+int BL_Shader::GetAttribLocation(const STR_String& name)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ return bgl::blGetAttribLocationARB(mShader, name.ReadPtr());
+ }
+#endif
+ return -1;
+}
+
+void BL_Shader::BindAttribute(const STR_String& attr, int loc)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ bgl::blBindAttribLocationARB(mShader, loc, attr.ReadPtr());
+ }
+#endif
+}
+
+int BL_Shader::GetUniformLocation(const STR_String& name)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ MT_assert(mShader!=0);
+ int location = bgl::blGetUniformLocationARB(mShader, name.ReadPtr());
+ if(location == -1)
+ spit("Invalid uniform value: " << name.ReadPtr() << ".");
+ return location;
+ }
+#endif
+ return -1;
+}
+
+void BL_Shader::SetUniform(int uniform, const MT_Tuple2& vec)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ float value[2];
+ vec.getValue(value);
+ bgl::blUniform2fvARB(uniform, 1, value);
+ }
+#endif
+
+}
+
+void BL_Shader::SetUniform(int uniform, const MT_Tuple3& vec)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ float value[3];
+ vec.getValue(value);
+ bgl::blUniform3fvARB(uniform, 1, value);
+ }
+#endif
+}
+
+void BL_Shader::SetUniform(int uniform, const MT_Tuple4& vec)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ float value[4];
+ vec.getValue(value);
+ bgl::blUniform4fvARB(uniform, 1, value);
+ }
+#endif
+}
+
+void BL_Shader::SetUniform(int uniform, const unsigned int& val)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ bgl::blUniform1iARB(uniform, val);
+ }
+#endif
+}
+
+void BL_Shader::SetUniform(int uniform, const int val)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ bgl::blUniform1iARB(uniform, val);
+ }
+#endif
+}
+
+void BL_Shader::SetUniform(int uniform, const float& val)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ bgl::blUniform1fARB(uniform, val);
+ }
+#endif
+}
+
+void BL_Shader::SetUniform(int uniform, const MT_Matrix4x4& vec, bool transpose)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ float value[16];
+ vec.getValue(value);
+ bgl::blUniformMatrix4fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value);
+ }
+#endif
+}
+
+void BL_Shader::SetUniform(int uniform, const MT_Matrix3x3& vec, bool transpose)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ float value[9];
+ value[0] = (float)vec[0][0]; value[1] = (float)vec[1][0]; value[2] = (float)vec[2][0];
+ value[3] = (float)vec[0][1]; value[4] = (float)vec[1][1]; value[5] = (float)vec[2][1];
+ value[6] = (float)vec[0][2]; value[7] = (float)vec[1][2]; value[7] = (float)vec[2][2];
+ bgl::blUniformMatrix3fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value);
+ }
+#endif
+}
+
+void BL_Shader::SetUniform(int uniform, const float* val, int len)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ if(len == 2)
+ bgl::blUniform2fvARB(uniform, 1,(GLfloat*)val);
+ else if (len == 3)
+ bgl::blUniform3fvARB(uniform, 1,(GLfloat*)val);
+ else if (len == 4)
+ bgl::blUniform4fvARB(uniform, 1,(GLfloat*)val);
+ else
+ MT_assert(0);
+ }
+#endif
+}
+
+void BL_Shader::SetUniform(int uniform, const int* val, int len)
+{
+#ifdef GL_ARB_shader_objects
+ if( RAS_EXT_support._ARB_fragment_shader &&
+ RAS_EXT_support._ARB_vertex_shader &&
+ RAS_EXT_support._ARB_shader_objects
+ )
+ {
+ if(len == 2)
+ bgl::blUniform2ivARB(uniform, 1, (GLint*)val);
+ else if (len == 3)
+ bgl::blUniform3ivARB(uniform, 1, (GLint*)val);
+ else if (len == 4)
+ bgl::blUniform4ivARB(uniform, 1, (GLint*)val);
+ else
+ MT_assert(0);
+ }
+#endif
+}
+
+
+PyObject* BL_Shader::_getattr(const STR_String& attr)
+{
+ _getattr_up(PyObjectPlus);
+}
+
+
+PyMethodDef BL_Shader::Methods[] =
+{
+ // creation
+ KX_PYMETHODTABLE( BL_Shader, setSource ),
+ KX_PYMETHODTABLE( BL_Shader, delSource ),
+ KX_PYMETHODTABLE( BL_Shader, getVertexProg ),
+ KX_PYMETHODTABLE( BL_Shader, getFragmentProg ),
+ KX_PYMETHODTABLE( BL_Shader, setNumberOfPasses ),
+ KX_PYMETHODTABLE( BL_Shader, validate),
+ /// access functions
+ KX_PYMETHODTABLE( BL_Shader, isValid),
+ KX_PYMETHODTABLE( BL_Shader, setUniform1f ),
+ KX_PYMETHODTABLE( BL_Shader, setUniform2f ),
+ KX_PYMETHODTABLE( BL_Shader, setUniform3f ),
+ KX_PYMETHODTABLE( BL_Shader, setUniform4f ),
+ KX_PYMETHODTABLE( BL_Shader, setUniform1i ),
+ KX_PYMETHODTABLE( BL_Shader, setUniform2i ),
+ KX_PYMETHODTABLE( BL_Shader, setUniform3i ),
+ KX_PYMETHODTABLE( BL_Shader, setUniform4i ),
+ KX_PYMETHODTABLE( BL_Shader, setAttrib ),
+
+ KX_PYMETHODTABLE( BL_Shader, setUniformfv ),
+ KX_PYMETHODTABLE( BL_Shader, setUniformiv ),
+ KX_PYMETHODTABLE( BL_Shader, setUniformDef ),
+
+ KX_PYMETHODTABLE( BL_Shader, setSampler ),
+ KX_PYMETHODTABLE( BL_Shader, setUniformMatrix4 ),
+ KX_PYMETHODTABLE( BL_Shader, setUniformMatrix3 ),
+
+ {NULL,NULL} //Sentinel
+};
+
+
+PyTypeObject BL_Shader::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "BL_Shader",
+ sizeof(BL_Shader),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0,
+ __repr,
+ 0
+};
+
+
+PyParentObject BL_Shader::Parents[] = {
+ &PyObjectPlus::Type,
+ &BL_Shader::Type,
+ NULL
+};
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, setSource," setSource(vertexProgram, fragmentProgram)" )
+{
+#ifdef GL_ARB_shader_objects
+ if(mShader !=0 && mOk )
+ {
+ // already set...
+ Py_Return;
+ }
+ char *v,*f;
+ int apply=0;
+ if( PyArg_ParseTuple(args, "ssi", &v, &f, &apply) )
+ {
+ vertProg = v;
+ fragProg = f;
+ if( LinkProgram() ) {
+ bgl::blUseProgramObjectARB( mShader );
+ mUse = apply!=0;
+ Py_Return;
+ }
+ vertProg = 0;
+ fragProg = 0;
+ mUse = 0;
+ Py_Return;
+ }
+ return NULL;
+#else
+ Py_Return;
+#endif
+}
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, delSource, "delSource( )" )
+{
+#ifdef GL_ARB_shader_objects
+ ClearUniforms();
+ bgl::blUseProgramObjectARB(0);
+
+ bgl::blDeleteObjectARB(mShader);
+ mShader = 0;
+ mOk = 0;
+ mUse = 0;
+#endif
+ Py_Return;
+}
+
+KX_PYMETHODDEF_DOC( BL_Shader, isValid, "isValid()" )
+{
+ return PyInt_FromLong( ( mShader !=0 && mOk ) );
+}
+
+KX_PYMETHODDEF_DOC( BL_Shader, getVertexProg ,"getVertexProg( )" )
+{
+ return PyString_FromString(vertProg?vertProg:"");
+}
+
+KX_PYMETHODDEF_DOC( BL_Shader, getFragmentProg ,"getFragmentProg( )" )
+{
+ return PyString_FromString(fragProg?fragProg:"");
+}
+
+KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()")
+{
+#ifdef GL_ARB_shader_objects
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ if(mShader==0) {
+ PyErr_Format(PyExc_TypeError, "invalid shader object");
+ return NULL;
+ }
+ int stat = 0;
+ bgl::blValidateProgramARB(mShader);
+ bgl::blGetObjectParameterivARB(mShader, GL_OBJECT_VALIDATE_STATUS_ARB,(GLint*) &stat);
+
+
+ if(stat > 0 && stat < MAX_LOG_LEN) {
+ int char_len=0;
+ char *logInf = (char*)MEM_mallocN(stat, "validate-log");
+
+ bgl::blGetInfoLogARB(mShader, stat,(GLsizei*) &char_len, logInf);
+ if(char_len >0) {
+ spit("---- GLSL Validation ----");
+ spit(logInf);
+ }
+ MEM_freeN(logInf);
+ logInf=0;
+ }
+#endif//GL_ARB_shader_objects
+ Py_Return;
+}
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" )
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ char *uniform="";
+ int index=-1;
+ if(PyArg_ParseTuple(args, "si", &uniform, &index))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1) {
+ if(index >= MAXTEX && index < 0)
+ spit("Invalid texture sample index: " << index);
+
+#ifdef SORT_UNIFORMS
+ SetUniformiv(loc, BL_Uniform::UNI_INT, &index, (sizeof(int)) );
+#else
+ SetUniform(loc, index);
+#endif
+ //if(index <= MAXTEX)
+ // mSampler[index].mLoc = loc;
+ //else
+ // spit("Invalid texture sample index: " << index);
+ }
+ Py_Return;
+ }
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC( BL_Shader, setNumberOfPasses, "setNumberOfPasses( max-pass )" )
+{
+ int pass = 1;
+ if(!PyArg_ParseTuple(args, "i", &pass))
+ return NULL;
+
+ mPass = 1;
+ Py_Return;
+}
+
+/// access functions
+KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" )
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ char *uniform="";
+ float value=0;
+ if(PyArg_ParseTuple(args, "sf", &uniform, &value ))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+#ifdef SORT_UNIFORMS
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT, &value, sizeof(float));
+#else
+ SetUniform( loc, (float)value );
+#endif
+ }
+ Py_Return;
+ }
+ return NULL;
+}
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f , "setUniform2f(name, fx, fy)")
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ char *uniform="";
+ float array[2]={ 0,0 };
+ if(PyArg_ParseTuple(args, "sff", &uniform, &array[0],&array[1] ))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+#ifdef SORT_UNIFORMS
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT2, array, (sizeof(float)*2) );
+#else
+ SetUniform(loc, array, 2);
+#endif
+ }
+ Py_Return;
+ }
+ return NULL;
+}
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ")
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ char *uniform="";
+ float array[3]={0,0,0};
+ if(PyArg_ParseTuple(args, "sfff", &uniform, &array[0],&array[1],&array[2]))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+#ifdef SORT_UNIFORMS
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT3, array, (sizeof(float)*3) );
+#else
+ SetUniform(loc, array, 3);
+#endif
+ }
+ Py_Return;
+
+ }
+ return NULL;
+}
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ")
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ char *uniform="";
+ float array[4]={0,0,0,0};
+ if(PyArg_ParseTuple(args, "sffff", &uniform, &array[0],&array[1],&array[2], &array[3]))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+#ifdef SORT_UNIFORMS
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT4, array, (sizeof(float)*4) );
+#else
+ SetUniform(loc, array, 4);
+#endif
+ }
+ Py_Return;
+ }
+ return NULL;
+}
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" )
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ char *uniform="";
+ int value=0;
+ if(PyArg_ParseTuple(args, "si", &uniform, &value ))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+#ifdef SORT_UNIFORMS
+ SetUniformiv(loc, BL_Uniform::UNI_INT, &value, sizeof(int));
+#else
+ SetUniform(loc, (int)value);
+#endif
+ }
+ Py_Return;
+ }
+ return NULL;
+}
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i , "setUniform2i(name, ix, iy)")
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ char *uniform="";
+ int array[2]={ 0,0 };
+ if(PyArg_ParseTuple(args, "sii", &uniform, &array[0],&array[1] ))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+#ifdef SORT_UNIFORMS
+ SetUniformiv(loc, BL_Uniform::UNI_INT2, array, sizeof(int)*2);
+#else
+ SetUniform(loc, array, 2);
+#endif
+ }
+ Py_Return;
+ }
+ return NULL;
+}
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ")
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ char *uniform="";
+ int array[3]={0,0,0};
+ if(PyArg_ParseTuple(args, "siii", &uniform, &array[0],&array[1],&array[2]))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+#ifdef SORT_UNIFORMS
+ SetUniformiv(loc, BL_Uniform::UNI_INT3, array, sizeof(int)*3);
+#else
+ SetUniform(loc, array, 3);
+#endif
+ }
+ Py_Return;
+ }
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) ")
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ char *uniform="";
+ int array[4]={0,0,0, 0};
+ if(PyArg_ParseTuple(args, "siiii", &uniform, &array[0],&array[1],&array[2], &array[3] ))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+#ifdef SORT_UNIFORMS
+ SetUniformiv(loc, BL_Uniform::UNI_INT4, array, sizeof(int)*4);
+#else
+ SetUniform(loc, array, 4);
+#endif
+ }
+ Py_Return;
+ }
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or list3 or list4) )")
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ char*uniform = "";
+ PyObject *listPtr =0;
+ float array_data[4] = {0.f,0.f,0.f,0.f};
+
+ if(PyArg_ParseTuple(args, "sO", &uniform, &listPtr))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+ if(PySequence_Check(listPtr))
+ {
+ unsigned int list_size = PySequence_Size(listPtr);
+
+ for(unsigned int i=0; (i<list_size && i<4); i++)
+ {
+ PyObject *item = PySequence_GetItem(listPtr, i);
+ array_data[i] = (float)PyFloat_AsDouble(item);
+ Py_DECREF(item);
+ }
+
+ switch(list_size)
+ {
+ case 2:
+ {
+ float array2[2] = { array_data[0],array_data[1] };
+#ifdef SORT_UNIFORMS
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT2, array2, sizeof(float)*2);
+#else
+ SetUniform(loc, array2, 2);
+#endif
+ Py_Return;
+ } break;
+ case 3:
+ {
+ float array3[3] = { array_data[0],array_data[1],array_data[2] };
+#ifdef SORT_UNIFORMS
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT3, array3, sizeof(float)*3);
+#else
+ SetUniform(loc, array3, 3);
+#endif
+ Py_Return;
+ }break;
+ case 4:
+ {
+ float array4[4] = { array_data[0],array_data[1],array_data[2],array_data[3] };
+#ifdef SORT_UNIFORMS
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT4, array4, sizeof(float)*4);
+#else
+ SetUniform(loc, array4, 4);
+#endif
+ Py_Return;
+ }break;
+ default:
+ {
+ PyErr_Format(PyExc_TypeError, "Invalid list size");
+ return NULL;
+ }break;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniformiv, "setUniformiv( int (list2 or list3 or list4) )")
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ char*uniform = "";
+ PyObject *listPtr =0;
+ int array_data[4] = {0,0,0,0};
+
+ if(PyArg_ParseTuple(args, "sO", &uniform, &listPtr))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+ if(PySequence_Check(listPtr))
+ {
+ unsigned int list_size = PySequence_Size(listPtr);
+
+ for(unsigned int i=0; (i<list_size && i<4); i++)
+ {
+ PyObject *item = PySequence_GetItem(listPtr, i);
+ array_data[i] = PyInt_AsLong(item);
+ Py_DECREF(item);
+ }
+ switch(list_size)
+ {
+ case 2:
+ {
+ int array2[2] = { array_data[0],array_data[1]};
+#ifdef SORT_UNIFORMS
+ SetUniformiv(loc, BL_Uniform::UNI_INT2, array2, sizeof(int)*2);
+#else
+ SetUniform(loc, array2, 2);
+#endif
+ Py_Return;
+ } break;
+ case 3:
+ {
+ int array3[3] = { array_data[0],array_data[1],array_data[2] };
+#ifdef SORT_UNIFORMS
+ SetUniformiv(loc, BL_Uniform::UNI_INT3, array3, sizeof(int)*3);
+
+#else
+ SetUniform(loc, array3, 3);
+#endif
+ Py_Return;
+ }break;
+ case 4:
+ {
+ int array4[4] = { array_data[0],array_data[1],array_data[2],array_data[3] };
+#ifdef SORT_UNIFORMS
+ SetUniformiv(loc, BL_Uniform::UNI_INT4, array4, sizeof(int)*4);
+
+#else
+ SetUniform(loc, array4, 4);
+#endif
+ Py_Return;
+ }break;
+ default:
+ {
+ PyErr_Format(PyExc_TypeError, "Invalid list size");
+ return NULL;
+ }break;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix4,
+"setUniformMatrix4(uniform-name, mat-4x4, transpose(row-major=true, col-major=false)" )
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ float matr[16] = {
+ 1,0,0,0,
+ 0,1,0,0,
+ 0,0,1,0,
+ 0,0,0,1
+ };
+
+ char *uniform="";
+ PyObject *matrix=0;
+ int transp=1; // MT_ is row major so transpose by default....
+ if(PyArg_ParseTuple(args, "sO|i",&uniform, &matrix,&transp))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+ if (PyObject_IsMT_Matrix(matrix, 4))
+ {
+ MT_Matrix4x4 mat;
+ if (PyMatTo(matrix, mat))
+ {
+#ifdef SORT_UNIFORMS
+ mat.getValue(matr);
+ SetUniformfv(loc, BL_Uniform::UNI_MAT4, matr, (sizeof(float)*16), (transp!=0) );
+#else
+ SetUniform(loc,mat,(transp!=0));
+#endif
+ Py_Return;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3,
+"setUniformMatrix3(uniform-name, list[3x3], transpose(row-major=true, col-major=false)" )
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ float matr[9] = {
+ 1,0,0,
+ 0,1,0,
+ 0,0,1,
+ };
+
+ char *uniform="";
+ PyObject *matrix=0;
+ int transp=1; // MT_ is row major so transpose by default....
+ if(PyArg_ParseTuple(args, "sO|i",&uniform, &matrix,&transp))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+ if (PyObject_IsMT_Matrix(matrix, 3))
+ {
+ MT_Matrix3x3 mat;
+ if (PyMatTo(matrix, mat))
+ {
+#ifdef SORT_UNIFORMS
+ mat.getValue(matr);
+ SetUniformfv(loc, BL_Uniform::UNI_MAT3, matr, (sizeof(float)*9), (transp!=0) );
+#else
+ SetUniform(loc,mat,(transp!=0));
+#endif
+ Py_Return;
+
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC( BL_Shader, setAttrib, "setAttrib(enum)" )
+{
+#ifdef GL_ARB_shader_objects
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ int attr=0;
+ if(PyArg_ParseTuple(args, "i", &attr )) {
+ if(mShader==0) {
+ PyErr_Format(PyExc_ValueError, "invalid shader object");
+ return NULL;
+ }
+ mAttr=SHD_TANGENT;
+ bgl::blUseProgramObjectARB(mShader);
+ bgl::blBindAttribLocationARB(mShader, mAttr, "Tangent");
+ Py_Return;
+ }
+ return NULL;
+#endif
+}
+
+
+KX_PYMETHODDEF_DOC( BL_Shader, setUniformDef, "setUniformDef(name, enum)" )
+{
+ if(mError) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ char *uniform="";
+ int nloc=0;
+ if(PyArg_ParseTuple(args, "si",&uniform, &nloc))
+ {
+ int loc = GetUniformLocation(uniform);
+ if(loc != -1)
+ {
+ bool defined = false;
+ BL_UniformVecDef::iterator it = mPreDef.begin();
+ while(it != mPreDef.end()) {
+ if((*it)->mLoc == loc) {
+ defined = true;
+ break;
+ }
+ it++;
+ }
+ if(defined)
+ {
+ Py_Return;
+ }
+
+ BL_DefUniform *uni = new BL_DefUniform();
+ uni->mLoc = loc;
+ uni->mType = nloc;
+ uni->mFlag = 0;
+ mPreDef.push_back(uni);
+ Py_Return;
+ }
+ }
+ return NULL;
+}
+
+// eof
diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h
new file mode 100644
index 00000000000..8f303454087
--- /dev/null
+++ b/source/gameengine/Ketsji/BL_Shader.h
@@ -0,0 +1,234 @@
+#ifndef __BL_SHADER_H__
+#define __BL_SHADER_H__
+
+#include "PyObjectPlus.h"
+#include "BL_Material.h"
+#include "BL_Texture.h"
+// --
+#include "MT_Matrix4x4.h"
+#include "MT_Matrix3x3.h"
+#include "MT_Tuple2.h"
+#include "MT_Tuple3.h"
+#include "MT_Tuple4.h"
+
+#define SHADER_ATTRIBMAX 1
+
+/**
+ * BL_Sampler
+ * Sampler access
+ */
+class BL_Sampler
+{
+public:
+ BL_Sampler():
+ mLoc(-1)
+ {
+ }
+ int mLoc; // Sampler location
+};
+
+/**
+ * BL_Uniform
+ * uniform storage
+ */
+class BL_Uniform
+{
+private:
+ int mLoc; // Uniform location
+ void* mData; // Memory allocated for variable
+ bool mDirty; // Caching variable
+ int mType; // Enum UniformTypes
+ bool mTranspose; // Transpose matrices
+ const int mDataLen; // Length of our data
+public:
+ BL_Uniform(int data_size);
+ ~BL_Uniform();
+
+
+ void Apply(class BL_Shader *shader);
+ void SetData(int location, int type, bool transpose=false);
+
+ enum UniformTypes {
+ UNI_NONE =0,
+ UNI_INT,
+ UNI_FLOAT,
+ UNI_INT2,
+ UNI_FLOAT2,
+ UNI_INT3,
+ UNI_FLOAT3,
+ UNI_INT4,
+ UNI_FLOAT4,
+ UNI_MAT3,
+ UNI_MAT4,
+ UNI_MAX
+ };
+
+ int GetLocation() { return mLoc; }
+ void* getData() { return mData; }
+};
+
+/**
+ * BL_DefUniform
+ * pre defined uniform storage
+ */
+class BL_DefUniform
+{
+public:
+ BL_DefUniform() :
+ mType(0),
+ mLoc(0),
+ mFlag(0)
+ {
+ }
+ int mType;
+ int mLoc;
+ unsigned int mFlag;
+};
+
+/**
+ * BL_Shader
+ * shader access
+ */
+class BL_Shader : public PyObjectPlus
+{
+ Py_Header;
+private:
+ typedef std::vector<BL_Uniform*> BL_UniformVec;
+ typedef std::vector<BL_DefUniform*> BL_UniformVecDef;
+
+ unsigned int mShader; // Shader object
+ int mPass; // 1.. unused
+ bool mOk; // Valid and ok
+ bool mUse; // ...
+//BL_Sampler mSampler[MAXTEX]; // Number of samplers
+ int mAttr; // Tangent attribute
+ char* vertProg; // Vertex program string
+ char* fragProg; // Fragment program string
+ bool mError; // ...
+ bool mDirty; //
+
+ // Compiles and links the shader
+ bool LinkProgram();
+
+ // Stored uniform variables
+ BL_UniformVec mUniforms;
+ BL_UniformVecDef mPreDef;
+
+ // search by location
+ BL_Uniform* FindUniform(const int location);
+ // clears uniform data
+ void ClearUniforms();
+
+public:
+ BL_Shader(PyTypeObject *T=&Type);
+ virtual ~BL_Shader();
+
+ // Unused for now tangent is set as
+ // tex coords
+ enum AttribTypes {
+ SHD_TANGENT =1
+ };
+
+ enum GenType {
+ MODELVIEWMATRIX,
+ MODELVIEWMATRIX_TRANSPOSE,
+ MODELVIEWMATRIX_INVERSE,
+ MODELVIEWMATRIX_INVERSETRANSPOSE,
+
+ // Model matrix
+ MODELMATRIX,
+ MODELMATRIX_TRANSPOSE,
+ MODELMATRIX_INVERSE,
+ MODELMATRIX_INVERSETRANSPOSE,
+
+ // View Matrix
+ VIEWMATRIX,
+ VIEWMATRIX_TRANSPOSE,
+ VIEWMATRIX_INVERSE,
+ VIEWMATRIX_INVERSETRANSPOSE,
+
+ // Current camera position
+ CAM_POS,
+
+ // RAS timer
+ CONSTANT_TIMER
+ };
+
+ const char* GetVertPtr();
+ const char* GetFragPtr();
+ void SetVertPtr( char *vert );
+ void SetFragPtr( char *frag );
+
+ // ---
+ int getNumPass() {return mPass;}
+ bool GetError() {return mError;}
+ // ---
+ //const BL_Sampler* GetSampler(int i);
+ void SetSampler(int loc, int unit);
+
+ const bool Ok()const;
+ unsigned int GetProg();
+ void SetProg(bool enable);
+ int GetAttribute(){return mAttr;};
+
+ // --
+ // Apply methods : sets colected uniforms
+ void ApplyShader();
+ void UnloadShader();
+
+ // Update predefined uniforms each render call
+ void Update(const class KX_MeshSlot & ms, class RAS_IRasterizer* rasty);
+
+ //// Set sampler units (copied)
+ //void InitializeSampler(int unit, BL_Texture* texture );
+
+
+ void SetUniformfv(int location,int type, float *param, int size,bool transpose=false);
+ void SetUniformiv(int location,int type, int *param, int size,bool transpose=false);
+
+ int GetAttribLocation(const STR_String& name);
+ void BindAttribute(const STR_String& attr, int loc);
+ int GetUniformLocation(const STR_String& name);
+
+ void SetUniform(int uniform, const MT_Tuple2& vec);
+ void SetUniform(int uniform, const MT_Tuple3& vec);
+ void SetUniform(int uniform, const MT_Tuple4& vec);
+ void SetUniform(int uniform, const MT_Matrix4x4& vec, bool transpose=false);
+ void SetUniform(int uniform, const MT_Matrix3x3& vec, bool transpose=false);
+ void SetUniform(int uniform, const float& val);
+ void SetUniform(int uniform, const float* val, int len);
+ void SetUniform(int uniform, const int* val, int len);
+ void SetUniform(int uniform, const unsigned int& val);
+ void SetUniform(int uniform, const int val);
+
+ // Python interface
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ // -----------------------------------
+ KX_PYMETHOD_DOC( BL_Shader, setSource );
+ KX_PYMETHOD_DOC( BL_Shader, delSource );
+ KX_PYMETHOD_DOC( BL_Shader, getVertexProg );
+ KX_PYMETHOD_DOC( BL_Shader, getFragmentProg );
+ KX_PYMETHOD_DOC( BL_Shader, setNumberOfPasses );
+ KX_PYMETHOD_DOC( BL_Shader, isValid);
+ KX_PYMETHOD_DOC( BL_Shader, validate);
+
+ // -----------------------------------
+ KX_PYMETHOD_DOC( BL_Shader, setUniform4f );
+ KX_PYMETHOD_DOC( BL_Shader, setUniform3f );
+ KX_PYMETHOD_DOC( BL_Shader, setUniform2f );
+ KX_PYMETHOD_DOC( BL_Shader, setUniform1f );
+ KX_PYMETHOD_DOC( BL_Shader, setUniform4i );
+ KX_PYMETHOD_DOC( BL_Shader, setUniform3i );
+ KX_PYMETHOD_DOC( BL_Shader, setUniform2i );
+ KX_PYMETHOD_DOC( BL_Shader, setUniform1i );
+ KX_PYMETHOD_DOC( BL_Shader, setUniformfv );
+ KX_PYMETHOD_DOC( BL_Shader, setUniformiv );
+ KX_PYMETHOD_DOC( BL_Shader, setUniformMatrix4 );
+ KX_PYMETHOD_DOC( BL_Shader, setUniformMatrix3 );
+ KX_PYMETHOD_DOC( BL_Shader, setUniformDef );
+ KX_PYMETHOD_DOC( BL_Shader, setAttrib );
+ KX_PYMETHOD_DOC( BL_Shader, setSampler);
+};
+
+#endif//__BL_SHADER_H__
diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp
new file mode 100644
index 00000000000..d6b57f062f2
--- /dev/null
+++ b/source/gameengine/Ketsji/BL_Texture.cpp
@@ -0,0 +1,723 @@
+// ------------------------------------
+#ifdef WIN32
+#include <windows.h>
+#endif // WIN32
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif
+
+#include <iostream>
+#include <map>
+
+#include "BL_Material.h"
+#include "BL_Texture.h"
+#include "MT_assert.h"
+
+#include "DNA_texture_types.h"
+#include "DNA_image_types.h"
+#include "IMB_imbuf_types.h"
+#include "BKE_image.h"
+#include "BLI_blenlib.h"
+
+#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
+#include "RAS_OpenGLRasterizer/ARB_multitexture.h"
+#include "RAS_ICanvas.h"
+#include "RAS_Rect.h"
+
+#include "KX_GameObject.h"
+
+
+using namespace bgl;
+
+#define spit(x) std::cout << x << std::endl;
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+ // envmaps
+ #include "IMB_imbuf.h"
+ void my_envmap_split_ima(EnvMap *env, ImBuf *ibuf);
+ void my_free_envmapdata(EnvMap *env);
+}
+
+// (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;
+}
+
+// Place holder for a full texture manager
+class BL_TextureObject
+{
+public:
+ unsigned int gl_texture;
+ void* ref_buffer;
+};
+
+typedef std::map<char*, BL_TextureObject> BL_TextureMap;
+static BL_TextureMap g_textureManager;
+
+
+BL_Texture::BL_Texture()
+: mTexture(0),
+ mOk(0),
+ mNeedsDeleted(0),
+ mType(0),
+ mUnit(0),
+ mEnvState(0)
+{
+ // --
+}
+
+BL_Texture::~BL_Texture()
+{
+ // --
+}
+
+void BL_Texture::DeleteTex()
+{
+ if( mNeedsDeleted ) {
+ glDeleteTextures(1, (GLuint*)&mTexture);
+ mNeedsDeleted = 0;
+ mOk = 0;
+ }
+
+ if(mEnvState) {
+ glDeleteLists((GLuint)mEnvState, 1);
+ mEnvState =0;
+ }
+
+ if(mDisableState) {
+ glDeleteLists((GLuint)mDisableState, 1);
+ mDisableState =0;
+ }
+ g_textureManager.clear();
+}
+
+
+bool BL_Texture::InitFromImage(int unit, Image *img, bool mipmap)
+{
+
+ ImBuf *ibuf;
+ if (!img || img->ok==0)
+ {
+ mOk = false;
+ return mOk;
+ }
+
+ ibuf= BKE_image_get_ibuf(img, NULL);
+ if (ibuf==NULL)
+ {
+ img->ok = 0;
+ mOk = false;
+ return mOk;
+ }
+
+
+ mTexture = img->bindcode;
+ mType = GL_TEXTURE_2D;
+ mUnit = unit;
+
+ ActivateUnit(mUnit);
+
+ if (mTexture != 0) {
+ glBindTexture(GL_TEXTURE_2D, mTexture );
+ Validate();
+ return mOk;
+ }
+
+ // look for an existing gl image
+ BL_TextureMap::iterator mapLook = g_textureManager.find(img->id.name);
+ if (mapLook != g_textureManager.end())
+ {
+ if (mapLook->second.gl_texture != 0)
+ {
+ mTexture = mapLook->second.gl_texture;
+ glBindTexture(GL_TEXTURE_2D, mTexture);
+ mOk = IsValid();
+ return mOk;
+ }
+ }
+
+ mNeedsDeleted = 1;
+ glGenTextures(1, (GLuint*)&mTexture);
+ InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap);
+
+ // track created units
+ BL_TextureObject obj;
+ obj.gl_texture = mTexture;
+ obj.ref_buffer = img;
+ g_textureManager.insert(std::pair<char*, BL_TextureObject>((char*)img->id.name, obj));
+
+
+ glDisable(GL_TEXTURE_2D);
+ ActivateUnit(0);
+ Validate();
+ return mOk;
+}
+
+void BL_Texture::InitGLTex(unsigned int *pix,int x,int y,bool mipmap)
+{
+ if (!is_pow2(x) || !is_pow2(y) ) {
+ InitNonPow2Tex(pix, x,y,mipmap);
+ return;
+ }
+
+ glBindTexture(GL_TEXTURE_2D, mTexture );
+ if( mipmap ) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, x, y, GL_RGBA, GL_UNSIGNED_BYTE, pix );
+ }
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix );
+ }
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+
+void BL_Texture::InitNonPow2Tex(unsigned int *pix,int x,int y,bool mipmap)
+{
+ int nx= smaller_pow2(x);
+ int ny= smaller_pow2(y);
+
+ unsigned int *newPixels = (unsigned int *)malloc(nx*ny*sizeof(unsigned int));
+
+ gluScaleImage(GL_RGBA, x, y, GL_UNSIGNED_BYTE, pix, nx,ny, GL_UNSIGNED_BYTE, newPixels);
+ glBindTexture(GL_TEXTURE_2D, mTexture );
+
+ if( mipmap ) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, nx, ny, GL_RGBA, GL_UNSIGNED_BYTE, newPixels );
+ }
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nx, ny, 0, GL_RGBA, GL_UNSIGNED_BYTE, newPixels );
+ }
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ free(newPixels);
+}
+
+
+bool BL_Texture::InitCubeMap(int unit, EnvMap *cubemap)
+{
+#ifdef GL_ARB_texture_cube_map
+
+ if (!RAS_EXT_support._ARB_texture_cube_map)
+ {
+ spit("cubemaps not supported");
+ mOk = false;
+ return mOk;
+ }
+ else if (!cubemap || cubemap->ima->ok==0)
+ {
+ mOk = false;
+ return mOk;
+ }
+
+ ImBuf *ibuf= BKE_image_get_ibuf(cubemap->ima, NULL);
+ if (ibuf==0)
+ {
+ cubemap->ima->ok = 0;
+ mOk = false;
+ return mOk;
+ }
+
+ mNeedsDeleted = 1;
+ mType = GL_TEXTURE_CUBE_MAP_ARB;
+ mTexture = 0;
+ mUnit = unit;
+
+ ActivateUnit(mUnit);
+
+ BL_TextureMap::iterator mapLook = g_textureManager.find(cubemap->ima->id.name);
+ if (mapLook != g_textureManager.end())
+ {
+ if (mapLook->second.gl_texture != 0 && mapLook->second.ref_buffer == cubemap->ima)
+ {
+ mTexture = mapLook->second.gl_texture;
+ glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mTexture);
+ mOk = IsValid();
+ return mOk;
+ }
+ }
+
+
+ glGenTextures(1, (GLuint*)&mTexture);
+ glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mTexture);
+
+
+ // track created units
+ BL_TextureObject obj;
+ obj.gl_texture = mTexture;
+ obj.ref_buffer = cubemap->ima;
+ g_textureManager.insert(std::pair<char*, BL_TextureObject>((char*)cubemap->ima->id.name, obj));
+
+
+ bool needs_split = false;
+ if (!cubemap->cube[0])
+ {
+ needs_split = true;
+ spit ("Re-Generating texture buffer");
+ }
+
+ if (needs_split)
+ my_envmap_split_ima(cubemap, ibuf);
+
+
+ if (!is_pow2(cubemap->cube[0]->x) || !is_pow2(cubemap->cube[0]->y))
+ {
+ spit("invalid envmap size please render with CubeRes @ power of two");
+
+ my_free_envmapdata(cubemap);
+ mOk = false;
+ return mOk;
+ }
+
+
+#define SetCubeMapFace(face, num) \
+ glTexImage2D(face, 0,GL_RGBA, \
+ cubemap->cube[num]->x, \
+ cubemap->cube[num]->y, \
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, \
+ cubemap->cube[num]->rect)
+
+ SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 5);
+ SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, 3);
+ SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, 0);
+ SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, 1);
+ SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, 2);
+ SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, 4);
+
+ glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ #ifdef GL_VERSION_1_2
+ glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
+ #endif
+
+ if (needs_split)
+ my_free_envmapdata(cubemap);
+
+
+
+ glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+ ActivateUnit(0);
+
+ mOk = IsValid();
+ return mOk;
+
+#else
+
+ mOk = false;
+ return mOk;
+
+#endif//GL_ARB_texture_cube_map
+}
+
+bool BL_Texture::IsValid()
+{
+ return (mTexture!= 0)?glIsTexture(mTexture)!=0:false;
+}
+
+
+void BL_Texture::Validate()
+{
+ mOk = IsValid();
+}
+
+
+bool BL_Texture::Ok()
+{
+ return (mTexture!= 0);
+}
+
+
+unsigned int BL_Texture::GetTextureType() const
+{
+ return mType;
+}
+
+int BL_Texture::GetMaxUnits()
+{
+ GLint unit=0;
+#ifdef GL_ARB_multitexture
+ if(RAS_EXT_support._ARB_multitexture) {
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &unit);
+ return (MAXTEX>=unit?unit:MAXTEX);
+ }
+#endif
+ return 0;
+}
+
+void BL_Texture::ActivateFirst()
+{
+#ifdef GL_ARB_multitexture
+ if(RAS_EXT_support._ARB_multitexture)
+ bgl::blActiveTextureARB(GL_TEXTURE0_ARB);
+#endif
+}
+
+void BL_Texture::ActivateUnit(int unit)
+{
+#ifdef GL_ARB_multitexture
+ if(RAS_EXT_support._ARB_multitexture)
+ if(unit <= MAXTEX)
+ bgl::blActiveTextureARB(GL_TEXTURE0_ARB+unit);
+#endif
+}
+
+
+void BL_Texture::DisableUnit()
+{
+#ifdef GL_ARB_multitexture
+ if(RAS_EXT_support._ARB_multitexture)
+ bgl::blActiveTextureARB(GL_TEXTURE0_ARB+mUnit);
+
+#endif
+
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+
+ #ifdef GL_ARB_texture_cube_map
+ if(RAS_EXT_support._ARB_texture_cube_map && glIsEnabled(GL_TEXTURE_CUBE_MAP_ARB))
+ glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+ else
+ #endif
+ {
+ if (glIsEnabled(GL_TEXTURE_2D))
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable(GL_TEXTURE_GEN_R);
+ glDisable(GL_TEXTURE_GEN_Q);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+}
+
+
+void BL_Texture::DisableAllTextures()
+{
+#ifdef GL_ARB_multitexture
+ glDisable(GL_BLEND);
+ for(int i=0; i<MAXTEX; i++) {
+ if(RAS_EXT_support._ARB_multitexture)
+ bgl::blActiveTextureARB(GL_TEXTURE0_ARB+i);
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable(GL_TEXTURE_GEN_R);
+ glDisable(GL_TEXTURE_GEN_Q);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+ }
+ if(RAS_EXT_support._ARB_multitexture)
+ bgl::blActiveTextureARB(GL_TEXTURE0_ARB);
+
+#endif
+}
+
+
+void BL_Texture::ActivateTexture()
+{
+#ifdef GL_ARB_multitexture
+ if(RAS_EXT_support._ARB_multitexture)
+ bgl::blActiveTextureARB(GL_TEXTURE0_ARB+mUnit);
+
+#ifdef GL_ARB_texture_cube_map
+ if (mType == GL_TEXTURE_CUBE_MAP_ARB && RAS_EXT_support._ARB_texture_cube_map)
+ {
+ glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, mTexture );
+ glEnable(GL_TEXTURE_CUBE_MAP_ARB);
+ }
+ else
+#endif
+ {
+
+ #ifdef GL_ARB_texture_cube_map
+ if(RAS_EXT_support._ARB_texture_cube_map )
+ glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+ #endif
+
+ glBindTexture( GL_TEXTURE_2D, mTexture );
+ glEnable(GL_TEXTURE_2D);
+ }
+#endif
+}
+
+void BL_Texture::SetMapping(int mode)
+{
+
+ if(!(mode &USEREFL)) {
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable(GL_TEXTURE_GEN_R);
+ glDisable(GL_TEXTURE_GEN_Q);
+ return;
+ }
+
+#ifdef GL_ARB_texture_cube_map
+ if( mType == GL_TEXTURE_CUBE_MAP_ARB &&
+ RAS_EXT_support._ARB_texture_cube_map &&
+ mode &USEREFL)
+ {
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB );
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB );
+ glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB );
+
+ glEnable(GL_TEXTURE_GEN_S);
+ glEnable(GL_TEXTURE_GEN_T);
+ glEnable(GL_TEXTURE_GEN_R);
+ glDisable(GL_TEXTURE_GEN_Q);
+ return;
+ }
+ else
+#endif
+ {
+ 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);
+ glDisable(GL_TEXTURE_GEN_R);
+ glDisable(GL_TEXTURE_GEN_Q);
+ }
+}
+
+
+void BL_Texture::setTexEnv(BL_Material *mat, bool modulate)
+{
+#ifndef GL_ARB_texture_env_combine
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+ return;
+#else
+ if(modulate || !RAS_EXT_support._ARB_texture_env_combine){
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+ return;
+ }
+
+ if(glIsList(mEnvState))
+ {
+ glCallList(mEnvState);
+ return;
+ }
+ if(!mEnvState)
+ mEnvState = glGenLists(1);
+
+ glNewList(mEnvState, GL_COMPILE_AND_EXECUTE);
+
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
+
+ GLfloat blend_operand = GL_SRC_COLOR;
+ GLfloat blend_operand_prev = GL_SRC_COLOR;
+ GLfloat alphaOp = GL_SRC_ALPHA;
+
+ GLenum combiner = GL_COMBINE_RGB_ARB;
+ GLenum source0 = GL_SOURCE0_RGB_ARB;
+ GLenum source1 = GL_SOURCE1_RGB_ARB;
+ GLenum source2 = GL_SOURCE2_RGB_ARB;
+ GLenum op0 = GL_OPERAND0_RGB_ARB;
+ GLenum op1 = GL_OPERAND1_RGB_ARB;
+ GLenum op2 = GL_OPERAND2_RGB_ARB;
+
+ // switch to alpha combiners
+ if( mat->flag[mUnit] &TEXALPHA ) {
+ combiner = GL_COMBINE_ALPHA_ARB;
+ source0 = GL_SOURCE0_ALPHA_ARB;
+ source1 = GL_SOURCE1_ALPHA_ARB;
+ source2 = GL_SOURCE2_ALPHA_ARB;
+ op0 = GL_OPERAND0_ALPHA_ARB;
+ op1 = GL_OPERAND1_ALPHA_ARB;
+ op2 = GL_OPERAND2_ALPHA_ARB;
+ blend_operand = GL_SRC_ALPHA;
+ blend_operand_prev = GL_SRC_ALPHA;
+ // invert
+ if(mat->flag[mUnit] &TEXNEG) {
+ blend_operand_prev = GL_ONE_MINUS_SRC_ALPHA;
+ blend_operand = GL_ONE_MINUS_SRC_ALPHA;
+ }
+ }
+ else {
+ if(mat->flag[mUnit] &TEXNEG) {
+ blend_operand_prev=GL_ONE_MINUS_SRC_COLOR;
+ blend_operand = GL_ONE_MINUS_SRC_COLOR;
+ }
+ }
+ bool using_alpha = false;
+
+ if(mat->flag[mUnit] &USEALPHA){
+ alphaOp = GL_ONE_MINUS_SRC_ALPHA;
+ using_alpha=true;
+ }
+ else if(mat->flag[mUnit] &USENEGALPHA){
+ alphaOp = GL_SRC_ALPHA;
+ using_alpha = true;
+ }
+
+ switch( mat->blend_mode[mUnit] ) {
+ case BLEND_MIX:
+ {
+ // ------------------------------
+ if(!using_alpha) {
+ GLfloat base_col[4];
+ base_col[0] = base_col[1] = base_col[2] = 0.f;
+ base_col[3] = 1.f-mat->color_blend[mUnit];
+ glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,base_col );
+ }
+ glTexEnvf( GL_TEXTURE_ENV, combiner, GL_INTERPOLATE_ARB);
+ glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB);
+ glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev );
+ glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE );
+ glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand);
+ if(!using_alpha)
+ glTexEnvf( GL_TEXTURE_ENV, source2, GL_CONSTANT_ARB );
+ else
+ glTexEnvf( GL_TEXTURE_ENV, source2, GL_TEXTURE );
+
+ glTexEnvf( GL_TEXTURE_ENV, op2, alphaOp);
+ }break;
+ case BLEND_MUL:
+ {
+ // ------------------------------
+ glTexEnvf( GL_TEXTURE_ENV, combiner, GL_MODULATE);
+ glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB);
+ glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev);
+ glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE );
+ if(using_alpha)
+ glTexEnvf( GL_TEXTURE_ENV, op1, alphaOp);
+ else
+ glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand);
+ }break;
+ case BLEND_ADD:
+ {
+ // ------------------------------
+ glTexEnvf( GL_TEXTURE_ENV, combiner, GL_ADD_SIGNED_ARB);
+ glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB );
+ glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev );
+ glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE );
+ if(using_alpha)
+ glTexEnvf( GL_TEXTURE_ENV, op1, alphaOp);
+ else
+ glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand);
+ }break;
+ case BLEND_SUB:
+ {
+ // ------------------------------
+ glTexEnvf( GL_TEXTURE_ENV, combiner, GL_SUBTRACT_ARB);
+ glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB );
+ glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev );
+ glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE );
+ glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand);
+ }break;
+ case BLEND_SCR:
+ {
+ // ------------------------------
+ glTexEnvf( GL_TEXTURE_ENV, combiner, GL_ADD);
+ glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB );
+ glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev );
+ glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE );
+ if(using_alpha)
+ glTexEnvf( GL_TEXTURE_ENV, op1, alphaOp);
+ else
+ glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand);
+ } break;
+ }
+ glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0);
+
+ glEndList();
+#endif //!GL_ARB_texture_env_combine
+}
+
+int BL_Texture::GetPow2(int n)
+{
+ if(!is_pow2(n))
+ n = smaller_pow2(n);
+
+ return n;
+}
+
+void BL_Texture::SplitEnvMap(EnvMap *map)
+{
+ if (!map || !map->ima || map->ima && !map->ima->ok) return;
+ ImBuf *ibuf= BKE_image_get_ibuf(map->ima, NULL);
+ if (ibuf)
+ my_envmap_split_ima(map, ibuf);
+}
+
+unsigned int BL_Texture::mDisableState = 0;
+
+extern "C" {
+
+void my_envmap_split_ima(EnvMap *env, ImBuf *ibuf)
+{
+ int dx, part;
+
+ my_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= 2;// ENV_OSA
+ }
+}
+
+
+void my_free_envmapdata(EnvMap *env)
+{
+ unsigned int part;
+
+ for(part=0; part<6; part++) {
+ ImBuf *ibuf= env->cube[part];
+ if(ibuf) {
+ IMB_freeImBuf(ibuf);
+ env->cube[part]= NULL;
+ }
+ }
+ env->ok= 0;
+}
+
+
+} // extern C
+
diff --git a/source/gameengine/Ketsji/BL_Texture.h b/source/gameengine/Ketsji/BL_Texture.h
new file mode 100644
index 00000000000..0d0c7a277f2
--- /dev/null
+++ b/source/gameengine/Ketsji/BL_Texture.h
@@ -0,0 +1,64 @@
+#ifndef __BL_TEXTURE_H__
+#define __BL_TEXTURE_H__
+
+// #include <vector>
+// #include <map>
+
+#include "MT_Matrix4x4.h"
+#include "KX_Camera.h"
+
+// --
+struct Image;
+struct EnvMap;
+class BL_Material;
+class RAS_Rect;
+class RAS_ICanvas;
+//class RTData;
+
+#include "STR_String.h"
+
+class BL_Texture
+{
+private:
+ unsigned int mTexture; // Bound texture unit data
+ bool mOk; // ...
+ bool mNeedsDeleted; // If generated
+ unsigned int mType; // enum TEXTURE_2D | CUBE_MAP
+ int mUnit; // Texture unit associated with mTexture
+ unsigned int mEnvState; // cache textureEnv
+ static unsigned int mDisableState; // speed up disabling calls
+
+ void InitNonPow2Tex(unsigned int *p,int x,int y,bool mipmap );
+ void InitGLTex(unsigned int *p,int x,int y,bool mipmap );
+public:
+ BL_Texture();
+ ~BL_Texture( );
+
+ bool Ok();
+ int GetUnit() {return mUnit;}
+ void SetUnit(int unit) {mUnit = unit;}
+
+ unsigned int GetTextureType() const;
+ void DeleteTex();
+
+ bool InitFromImage(int unit, Image *img, bool mipmap);
+ bool InitCubeMap(int unit,EnvMap *cubemap );
+
+ bool IsValid();
+ void Validate();
+
+ static void ActivateFirst();
+ static void DisableAllTextures();
+ static void ActivateUnit(int unit);
+ static int GetMaxUnits();
+ static int GetPow2(int x);
+ static void SplitEnvMap(EnvMap *map);
+
+
+ void ActivateTexture();
+ void SetMapping(int mode);
+ void DisableUnit();
+ void setTexEnv(BL_Material *mat, bool modulate=false);
+};
+
+#endif//__BL_TEXTURE_H__
diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt
new file mode 100644
index 00000000000..ca21869c007
--- /dev/null
+++ b/source/gameengine/Ketsji/CMakeLists.txt
@@ -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) 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 *.cpp)
+
+SET(INC
+ .
+ ../../../source/kernel/gen_system
+ ../../../intern/string
+ ../../../intern/guardedalloc
+ ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer
+ ../../../intern/bmfont
+ ../../../source/gameengine/Converter
+ ../../../source/blender/imbuf
+ ../../../intern/ghost/include
+ ../../../intern/moto/include
+ ../../../source/gameengine/Ketsji
+ ../../../source/blender/blenlib
+ ../../../source/blender/blenkernel
+ ../../../source/blender
+ ../../../source/blender/include
+ ../../../source/blender/makesdna
+ ../../../source/gameengine/Rasterizer
+ ../../../source/gameengine/GameLogic
+ ../../../source/gameengine/Expressions
+ ../../../source/gameengine/Ketsji/KXNetwork
+ ../../../source/gameengine/Network
+ ../../../source/gameengine/SceneGraph
+ ../../../source/gameengine/Physics/common
+ ../../../source/gameengine/Physics/Bullet
+ ../../../source/gameengine/Physics/Sumo
+ ../../../source/gameengine/Physics/Sumo/Fuzzics/include
+ ../../../source/gameengine/Network/LoopBackNetwork
+ ../../../intern/SoundSystem
+ ../../../source/blender/misc
+ ../../../source/blender/blenloader
+ ../../../extern/bullet2/src
+ ../../../extern/solid
+ ${PYTHON_INC}
+ ${SDL_INC}
+)
+
+BLENDERLIB(bf_ketsji "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_ketsji', sources, Split(incs), [], libtype=['game','player'], priority=[25, 72], compileflags = cflags )
diff --git a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt
new file mode 100644
index 00000000000..5a02c5ddb0e
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/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 *.cpp)
+
+SET(INC
+ .
+ ../../../../source/kernel/gen_system
+ ../../../../intern/string
+ ../../../../source/gameengine/Ketsji
+ ../../../../source/gameengine/GameLogic
+ ../../../../source/gameengine/Expressions
+ ../../../../source/gameengine/Network
+ ${PYTHON_INC}
+)
+
+BLENDERLIB(kx_network "${SRC}" "${INC}")
+#env.BlenderLib ( 'kx_network', Split(sources), Split(incs), defines=[],libtype=['game2', 'player'], priority=[5, 155] )
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp
new file mode 100644
index 00000000000..93c7ab37edb
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp
@@ -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 *****
+ * Ketsji Logic Extenstion: Network Event Manager generic implementation
+ */
+
+// Ketsji specific sensor part
+#include "SCA_ISensor.h"
+
+// Ketsji specific network part
+#include "KX_NetworkEventManager.h"
+
+// Network module specific
+#include "NG_NetworkDeviceInterface.h"
+#include "NG_NetworkMessage.h"
+#include "NG_NetworkObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_NetworkEventManager::KX_NetworkEventManager(class SCA_LogicManager*
+logicmgr, class NG_NetworkDeviceInterface *ndi) :
+SCA_EventManager(NETWORK_EVENTMGR), m_logicmgr(logicmgr), m_ndi(ndi)
+{
+ //printf("KX_NetworkEventManager constructor\n");
+}
+
+KX_NetworkEventManager::~KX_NetworkEventManager()
+{
+ //printf("KX_NetworkEventManager destructor\n");
+}
+
+void KX_NetworkEventManager::RegisterSensor(class SCA_ISensor* sensor)
+{
+ //printf("KX_NetworkEventManager RegisterSensor\n");
+ m_sensors.push_back(sensor);
+}
+
+void KX_NetworkEventManager::RemoveSensor(class SCA_ISensor* sensor)
+{
+ //printf("KX_NetworkEventManager RemoveSensor\n");
+ // Network specific RemoveSensor stuff goes here
+
+ // parent
+ SCA_EventManager::RemoveSensor(sensor);
+}
+
+void KX_NetworkEventManager::NextFrame()
+{
+// printf("KX_NetworkEventManager::proceed %.2f - %.2f\n", curtime, deltatime);
+ // each frame, the logicmanager will call the network
+ // eventmanager to look for network events, and process it's
+ // 'network' sensors
+ vector<class SCA_ISensor*>::iterator it;
+
+ for (it = m_sensors.begin(); !(it==m_sensors.end()); it++) {
+// printf("KX_NetworkEventManager::proceed sensor %.2f\n", curtime);
+ // process queue
+ (*it)->Activate(m_logicmgr, NULL);
+ }
+
+ // now a list of triggerer sensors has been built
+}
+
+void KX_NetworkEventManager::EndFrame()
+{
+}
+
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h
new file mode 100644
index 00000000000..9c0d14674c1
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.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 *****
+ * Ketsji Logic Extenstion: Network Event Manager class
+ */
+#ifndef KX_NETWORK_EVENTMANAGER_H
+#define KX_NETWORK_EVENTMANAGER_H
+
+#include "SCA_EventManager.h"
+
+class KX_NetworkEventManager : public SCA_EventManager
+{
+ class SCA_LogicManager* m_logicmgr;
+ class NG_NetworkDeviceInterface* m_ndi;
+
+public:
+ KX_NetworkEventManager(class SCA_LogicManager* logicmgr,
+ class NG_NetworkDeviceInterface *ndi);
+ virtual ~KX_NetworkEventManager ();
+
+ virtual void RegisterSensor(class SCA_ISensor* sensor);
+ virtual void RemoveSensor(class SCA_ISensor* sensor);
+
+ virtual void NextFrame();
+ virtual void EndFrame();
+
+ SCA_LogicManager* GetLogicManager() { return m_logicmgr; }
+ class NG_NetworkDeviceInterface* GetNetworkDevice() {
+ return m_ndi; }
+};
+
+#endif //KX_NETWORK_EVENTMANAGER_H
+
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp
new file mode 100644
index 00000000000..e142d2a1a1b
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp
@@ -0,0 +1,212 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Ketsji Logic Extenstion: Network Message Actuator generic implementation
+ */
+
+#include "NG_NetworkScene.h"
+#include "KX_NetworkMessageActuator.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_NetworkMessageActuator::KX_NetworkMessageActuator(
+ SCA_IObject* gameobj, // the actuator controlling object
+ NG_NetworkScene* networkscene, // needed for replication
+ const STR_String &toPropName,
+ const STR_String &subject,
+ int bodyType,
+ const STR_String &body,
+ PyTypeObject* T) :
+ SCA_IActuator(gameobj,T),
+ m_networkscene(networkscene),
+ m_toPropName(toPropName),
+ m_subject(subject),
+ m_bodyType(bodyType),
+ m_body(body)
+{
+}
+
+KX_NetworkMessageActuator::~KX_NetworkMessageActuator()
+{
+}
+
+// returns true if the actuators needs to be running over several frames
+bool KX_NetworkMessageActuator::Update()
+{
+ //printf("update messageactuator\n");
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (bNegativeEvent) {
+ return false; // do nothing on negative events
+ //printf("messageactuator false event\n");
+ }
+ //printf("messageactuator true event\n");
+
+ if (m_bodyType == 1) // ACT_MESG_PROP in DNA_actuator_types.h
+ {
+ m_networkscene->SendMessage(
+ m_toPropName,
+ GetParent()->GetName(),
+ m_subject,
+ GetParent()->GetPropertyText(m_body,""));
+ } else
+ {
+ m_networkscene->SendMessage(
+ m_toPropName,
+ GetParent()->GetName(),
+ m_subject,
+ m_body);
+ }
+ return false;
+}
+
+CValue* KX_NetworkMessageActuator::GetReplica()
+{
+ KX_NetworkMessageActuator* replica =
+ new KX_NetworkMessageActuator(*this);
+ replica->ProcessReplica();
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+/* -------------------------------------------------------------------- */
+/* Python interface --------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+
+/* Integration hooks -------------------------------------------------- */
+PyTypeObject KX_NetworkMessageActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_NetworkMessageActuator",
+ sizeof(KX_NetworkMessageActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_NetworkMessageActuator::Parents[] = {
+ &KX_NetworkMessageActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_NetworkMessageActuator::Methods[] = {
+ {"setToPropName", (PyCFunction)
+ KX_NetworkMessageActuator::sPySetToPropName, METH_VARARGS},
+ {"setSubject", (PyCFunction)
+ KX_NetworkMessageActuator::sPySetSubject, METH_VARARGS},
+ {"setBodyType", (PyCFunction)
+ KX_NetworkMessageActuator::sPySetBodyType, METH_VARARGS},
+ {"setBody", (PyCFunction)
+ KX_NetworkMessageActuator::sPySetBody, METH_VARARGS},
+ {NULL,NULL} // Sentinel
+};
+
+PyObject* KX_NetworkMessageActuator::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IActuator);
+}
+
+// 1. SetToPropName
+PyObject* KX_NetworkMessageActuator::PySetToPropName(
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ char* ToPropName;
+
+ if (PyArg_ParseTuple(args, "s", &ToPropName)) {
+ m_toPropName = ToPropName;
+ }
+
+ Py_Return;
+}
+
+// 2. SetSubject
+PyObject* KX_NetworkMessageActuator::PySetSubject(
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ char* Subject;
+
+ if (PyArg_ParseTuple(args, "s", &Subject)) {
+ m_subject = Subject;
+ }
+
+ Py_Return;
+}
+
+// 3. SetBodyType
+PyObject* KX_NetworkMessageActuator::PySetBodyType(
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int BodyType;
+
+ if (PyArg_ParseTuple(args, "i", &BodyType)) {
+ m_bodyType = BodyType;
+ }
+
+ Py_Return;
+}
+
+// 4. SetBody
+PyObject* KX_NetworkMessageActuator::PySetBody(
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ char* Body;
+
+ if (PyArg_ParseTuple(args, "s", &Body)) {
+ m_body = Body;
+ }
+
+ Py_Return;
+}
+
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h
new file mode 100644
index 00000000000..c81437dbd91
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.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 *****
+ * Ketsji Logic Extenstion: Network Message Actuator class
+ */
+#ifndef __KX_NETWORKMESSAGEACTUATOR_H
+#define __KX_NETWORKMESSAGEACTUATOR_H
+
+#include "STR_String.h"
+#include "SCA_IActuator.h"
+#include "NG_NetworkMessage.h"
+
+class KX_NetworkMessageActuator : public SCA_IActuator
+{
+ Py_Header;
+ bool m_lastEvent;
+ class NG_NetworkScene* m_networkscene; // needed for replication
+ STR_String m_toPropName;
+ STR_String m_subject;
+ int m_bodyType;
+ STR_String m_body;
+public:
+ KX_NetworkMessageActuator(
+ SCA_IObject* gameobj,
+ NG_NetworkScene* networkscene,
+ const STR_String &toPropName,
+ const STR_String &subject,
+ int bodyType,
+ const STR_String &body,
+ PyTypeObject* T=&Type);
+ virtual ~KX_NetworkMessageActuator();
+
+ virtual bool Update();
+ virtual CValue* GetReplica();
+
+ /* ------------------------------------------------------------ */
+ /* Python interface ------------------------------------------- */
+ /* ------------------------------------------------------------ */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ KX_PYMETHOD(KX_NetworkMessageActuator, SetToPropName);
+ KX_PYMETHOD(KX_NetworkMessageActuator, SetSubject);
+ KX_PYMETHOD(KX_NetworkMessageActuator, SetBodyType);
+ KX_PYMETHOD(KX_NetworkMessageActuator, SetBody);
+
+};
+
+#endif //__KX_NETWORKMESSAGEACTUATOR_H
+
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp
new file mode 100644
index 00000000000..86f114b2f51
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp
@@ -0,0 +1,296 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Ketsji Logic Extenstion: Network Message Sensor generic implementation
+ */
+
+#include "KX_NetworkMessageSensor.h"
+#include "KX_NetworkEventManager.h"
+#include "NG_NetworkMessage.h"
+#include "NG_NetworkScene.h"
+#include "NG_NetworkObject.h"
+#include "SCA_IObject.h"
+#include "InputParser.h"
+#include "ListValue.h"
+#include "StringValue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef NAN_NET_DEBUG
+ #include <iostream>
+#endif
+
+KX_NetworkMessageSensor::KX_NetworkMessageSensor(
+ class KX_NetworkEventManager* eventmgr, // our eventmanager
+ class NG_NetworkScene *NetworkScene, // our scene
+ SCA_IObject* gameobj, // the sensor controlling object
+ const STR_String &subject,
+ PyTypeObject* T
+) :
+ SCA_ISensor(gameobj,eventmgr,T),
+ m_Networkeventmgr(eventmgr),
+ m_NetworkScene(NetworkScene),
+ m_subject(subject),
+ m_frame_message_count (0),
+ m_IsUp(false),
+ m_BodyList(NULL),
+ m_SubjectList(NULL)
+{
+}
+
+KX_NetworkMessageSensor::~KX_NetworkMessageSensor()
+{
+}
+
+CValue* KX_NetworkMessageSensor::GetReplica() {
+ // This is the standard sensor implementation of GetReplica
+ // There may be more network message sensor specific stuff to do here.
+ CValue* replica = new KX_NetworkMessageSensor(*this);
+
+ if (replica == NULL) return NULL;
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+// Return true only for flank (UP and DOWN)
+bool KX_NetworkMessageSensor::Evaluate(CValue* event)
+{
+ bool result = false;
+ bool WasUp = m_IsUp;
+
+ m_IsUp = false;
+
+ if (m_BodyList) {
+ m_BodyList->Release();
+ m_BodyList = NULL;
+ }
+
+ if (m_SubjectList) {
+ m_SubjectList->Release();
+ m_SubjectList = NULL;
+ }
+
+ STR_String toname=GetParent()->GetName();
+ STR_String subject = this->m_subject;
+
+ vector<NG_NetworkMessage*> messages =
+ m_NetworkScene->FindMessages(toname,"",subject,true);
+
+ m_frame_message_count = messages.size();
+
+ if (!messages.empty()) {
+#ifdef NAN_NET_DEBUG
+ printf("KX_NetworkMessageSensor found one or more messages\n");
+#endif
+ m_IsUp = true;
+ m_BodyList = new CListValue();
+ m_SubjectList = new CListValue();
+ }
+
+ vector<NG_NetworkMessage*>::iterator mesit;
+ for (mesit=messages.begin();mesit!=messages.end();mesit++)
+ {
+ // save the body
+ STR_String body = (*mesit)->GetMessageText();
+ // save the subject
+ STR_String messub = (*mesit)->GetSubject();
+#ifdef NAN_NET_DEBUG
+ if (body) {
+ cout << "body [" << body << "]\n";
+ }
+#endif
+ m_BodyList->Add(new CStringValue(body,"body"));
+ // Store Subject
+ m_SubjectList->Add(new CStringValue(messub,"subject"));
+
+ // free the message
+ (*mesit)->Release();
+ }
+ messages.clear();
+
+ result = (WasUp != m_IsUp);
+
+ // Return true if the message received state has changed.
+ return result;
+}
+
+// return true for being up (no flank needed)
+bool KX_NetworkMessageSensor::IsPositiveTrigger()
+{
+// printf("KX_NetworkMessageSensor IsPositiveTrigger\n");
+ //attempt to fix [ #3809 ] IPO Actuator does not work with some Sensors
+ //a better solution is to properly introduce separate Edge and Level triggering concept
+
+ return m_IsUp;
+}
+
+/* --------------------------------------------------------------------- */
+/* Python interface ---------------------------------------------------- */
+/* --------------------------------------------------------------------- */
+
+/* Integration hooks --------------------------------------------------- */
+PyTypeObject KX_NetworkMessageSensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_NetworkMessageSensor",
+ sizeof(KX_NetworkMessageSensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_NetworkMessageSensor::Parents[] = {
+ &KX_NetworkMessageSensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_NetworkMessageSensor::Methods[] = {
+ {"setSubjectFilterText", (PyCFunction)
+ KX_NetworkMessageSensor::sPySetSubjectFilterText, METH_VARARGS,
+ SetSubjectFilterText_doc},
+ {"getFrameMessageCount", (PyCFunction)
+ KX_NetworkMessageSensor::sPyGetFrameMessageCount, METH_VARARGS,
+ GetFrameMessageCount_doc},
+ {"getBodies", (PyCFunction)
+ KX_NetworkMessageSensor::sPyGetBodies, METH_VARARGS,
+ GetBodies_doc},
+ {"getSubject", (PyCFunction)
+ KX_NetworkMessageSensor::sPyGetSubject, METH_VARARGS,
+ GetSubject_doc},
+ {"getSubjects", (PyCFunction)
+ KX_NetworkMessageSensor::sPyGetSubjects, METH_VARARGS,
+ GetSubjects_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* KX_NetworkMessageSensor::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_ISensor); // implicit return!
+}
+
+// 1. Set the message subject that this sensor listens for
+char KX_NetworkMessageSensor::SetSubjectFilterText_doc[] =
+"\tsetSubjectFilterText(value)\n"
+"\tChange the message subject text that this sensor is listening to.\n";
+
+PyObject* KX_NetworkMessageSensor::PySetSubjectFilterText(
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ char* Subject;
+
+ if (PyArg_ParseTuple(args, "s", &Subject))
+ {
+ m_subject = Subject;
+ }
+
+ Py_Return;
+}
+
+// 2. Get the number of messages received since the last frame
+char KX_NetworkMessageSensor::GetFrameMessageCount_doc[] =
+"\tgetFrameMessageCount()\n"
+"\tGet the number of messages received since the last frame.\n";
+
+PyObject* KX_NetworkMessageSensor::PyGetFrameMessageCount(
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyInt_FromLong(long(m_frame_message_count));
+}
+
+// 3. Get the message bodies
+char KX_NetworkMessageSensor::GetBodies_doc[] =
+"\tgetBodies()\n"
+"\tGet the list of message bodies.\n";
+
+PyObject* KX_NetworkMessageSensor::PyGetBodies(
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ if (m_BodyList) {
+ return ((PyObject*) m_BodyList->AddRef());
+ }
+
+ Py_Return;
+}
+
+// 4. Get the message subject: field of the message sensor
+char KX_NetworkMessageSensor::GetSubject_doc[] =
+"\tgetSubject()\n"
+"\tGet the subject: field of the message sensor.\n";
+
+PyObject* KX_NetworkMessageSensor::PyGetSubject(
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ if (m_subject) {
+ return PyString_FromString(m_subject);
+ }
+
+ Py_Return;
+}
+
+// 5. Get the message subjects
+char KX_NetworkMessageSensor::GetSubjects_doc[] =
+"\tgetSubjects()\n"
+"\tGet list of message subjects.\n";
+
+PyObject* KX_NetworkMessageSensor::PyGetSubjects(
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ if (m_SubjectList) {
+ return ((PyObject*) m_SubjectList->AddRef());
+ }
+
+ Py_Return;
+}
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h
new file mode 100644
index 00000000000..82f83787645
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h
@@ -0,0 +1,89 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Ketsji Logic Extenstion: Network Message Sensor class
+ */
+#ifndef __KX_NETWORKMESSAGE_SENSOR_H
+#define __KX_NETWORKMESSAGE_SENSOR_H
+
+#include "SCA_ISensor.h"
+
+class KX_NetworkEventManager;
+class NG_NetworkScene;
+
+class KX_NetworkMessageSensor : public SCA_ISensor
+{
+ // note: Py_Header MUST BE the first listed here
+ Py_Header;
+ KX_NetworkEventManager *m_Networkeventmgr;
+ NG_NetworkScene *m_NetworkScene;
+
+ // The subject we filter on.
+ STR_String m_subject;
+
+ // The number of messages caught since the last frame.
+ int m_frame_message_count;
+
+ bool m_IsUp;
+
+ class CListValue* m_BodyList;
+ class CListValue* m_SubjectList;
+public:
+ KX_NetworkMessageSensor(
+ KX_NetworkEventManager* eventmgr, // our eventmanager
+ NG_NetworkScene *NetworkScene, // our scene
+ SCA_IObject* gameobj, // the sensor controlling object
+ const STR_String &subject,
+ PyTypeObject* T=&Type
+ );
+ virtual ~KX_NetworkMessageSensor();
+
+ virtual CValue* GetReplica();
+ virtual bool Evaluate(CValue* event);
+ virtual bool IsPositiveTrigger();
+ void EndFrame();
+
+ /* ------------------------------------------------------------- */
+ /* Python interface -------------------------------------------- */
+ /* ------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ KX_PYMETHOD_DOC(KX_NetworkMessageSensor, SetSubjectFilterText);
+ KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetFrameMessageCount);
+ KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetBodies);
+ KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetSubject);
+ KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetSubjects);
+
+
+};
+
+#endif //__KX_NETWORKMESSAGE_SENSOR_H
+
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.cpp
new file mode 100644
index 00000000000..a27ac01d5c4
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.cpp
@@ -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 *****
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.h
new file mode 100644
index 00000000000..39910963161
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.h
@@ -0,0 +1,32 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.cpp
new file mode 100644
index 00000000000..9da25bcb70b
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.cpp
@@ -0,0 +1,36 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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
+
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.h
new file mode 100644
index 00000000000..39910963161
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.h
@@ -0,0 +1,32 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
diff --git a/source/gameengine/Ketsji/KXNetwork/Makefile b/source/gameengine/Ketsji/KXNetwork/Makefile
new file mode 100644
index 00000000000..ee8ddc45c3b
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/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 = KXNetwork
+DIR = $(OCGDIR)/gameengine/ketsji/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I../../Expressions
+CPPFLAGS += -I../../GameLogic
+CPPFLAGS += -I../../Network
+CPPFLAGS += -I../../../kernel/gen_system
+CPPFLAGS += -I..
+
diff --git a/source/gameengine/Ketsji/KXNetwork/SConscript b/source/gameengine/Ketsji/KXNetwork/SConscript
new file mode 100644
index 00000000000..2297b96c19e
--- /dev/null
+++ b/source/gameengine/Ketsji/KXNetwork/SConscript
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('*.cpp')
+
+incs = '. #source/kernel/gen_system #intern/string #source/gameengine/Ketsji'
+incs += ' #source/gameengine/GameLogic #source/gameengine/Expressions'
+incs += ' #source/gameengine/Network'
+
+incs += ' ' + env['BF_PYTHON_INC']
+
+env.BlenderLib ( 'kx_network', Split(sources), Split(incs), defines=[],libtype=['game2', 'player'], priority=[5, 155] )
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
new file mode 100644
index 00000000000..fa1c67f251c
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
@@ -0,0 +1,771 @@
+
+// ------------------------------------
+// ...
+// ------------------------------------
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+#endif // WIN32
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif
+
+#include "KX_BlenderMaterial.h"
+#include "BL_Material.h"
+#include "KX_Scene.h"
+#include "KX_Light.h"
+#include "KX_GameObject.h"
+#include "KX_MeshProxy.h"
+
+#include "MT_Vector3.h"
+#include "MT_Vector4.h"
+#include "MT_Matrix4x4.h"
+
+#include "RAS_MeshObject.h"
+#include "RAS_IRasterizer.h"
+#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
+#include "RAS_OpenGLRasterizer/ARB_multitexture.h"
+
+extern "C" {
+#include "BDR_drawmesh.h"
+}
+
+#include "STR_HashedString.h"
+
+// ------------------------------------
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_image_types.h"
+#include "DNA_meshdata_types.h"
+#include "BKE_mesh.h"
+// ------------------------------------
+using namespace bgl;
+#define spit(x) std::cout << x << std::endl;
+
+//static PyObject *gTextureDict = 0;
+
+KX_BlenderMaterial::KX_BlenderMaterial(
+ KX_Scene *scene,
+ BL_Material *data,
+ bool skin,
+ int lightlayer,
+ void *clientobject,
+ PyTypeObject *T
+ )
+: PyObjectPlus(T),
+ RAS_IPolyMaterial(
+ STR_String( data->texname[0] ),
+ STR_String( data->matname ), // needed for physics!
+ data->tile,
+ data->tilexrep[0],
+ data->tileyrep[0],
+ data->mode,
+ ((data->ras_mode &TRANSP)!=0),
+ ((data->ras_mode &ZSORT)!=0),
+ lightlayer,
+ ((data->ras_mode &TRIANGLE)!=0),
+ clientobject
+ ),
+ mMaterial(data),
+ mShader(0),
+ mScene(scene),
+ mUserDefBlend(0),
+ mModified(0),
+ mPass(0)
+
+{
+ // --------------------------------
+ // RAS_IPolyMaterial variables...
+ m_flag |=RAS_BLENDERMAT;
+ m_flag |=(mMaterial->IdMode>=ONETEX)?RAS_MULTITEX:0;
+ m_flag |=(mMaterial->ras_mode & USE_LIGHT)!=0?RAS_MULTILIGHT:0;
+ m_flag |=(mMaterial->ras_mode &ALPHA_TEST)!=0?RAS_FORCEALPHA:0;
+
+ // figure max
+ int enabled = mMaterial->num_enabled;
+ int max = BL_Texture::GetMaxUnits();
+ mMaterial->num_enabled = enabled>=max?max:enabled;
+
+ // base class
+ m_enabled = mMaterial->num_enabled;
+
+ // test the sum of the various modes for equality
+ // so we can ether accept or reject this material
+ // as being equal, this is rather important to
+ // prevent material bleeding
+ for(int i=0; i<mMaterial->num_enabled; i++) {
+ m_multimode +=
+ ( mMaterial->flag[i] +
+ mMaterial->blend_mode[i]
+ );
+ }
+ m_multimode += mMaterial->IdMode+mMaterial->ras_mode;
+
+}
+
+KX_BlenderMaterial::~KX_BlenderMaterial()
+{
+ // cleanup work
+ OnExit();
+}
+
+
+MTFace* KX_BlenderMaterial::GetMTFace(void) const
+{
+ // fonts on polys
+ MT_assert(mMaterial->tface);
+ return mMaterial->tface;
+}
+
+unsigned int* KX_BlenderMaterial::GetMCol(void) const
+{
+ // fonts on polys
+ return mMaterial->rgb;
+}
+
+void KX_BlenderMaterial::OnConstruction()
+{
+ // for each unique material...
+ int i;
+ for(i=0; i<mMaterial->num_enabled; i++) {
+ if( mMaterial->mapping[i].mapping & USEENV ) {
+ if(!RAS_EXT_support._ARB_texture_cube_map) {
+ spit("CubeMap textures not supported");
+ continue;
+ }
+ if(!mTextures[i].InitCubeMap(i, mMaterial->cubemap[i] ) )
+ spit("unable to initialize image("<<i<<") in "<<
+ mMaterial->matname<< ", image will not be available");
+ }
+
+ else {
+ if( mMaterial->img[i] ) {
+ if( ! mTextures[i].InitFromImage(i, mMaterial->img[i], (mMaterial->flag[i] &MIPMAP)!=0 ))
+ spit("unable to initialize image("<<i<<") in "<<
+ mMaterial->matname<< ", image will not be available");
+ }
+ }
+ }
+ mBlendFunc[0] =0;
+ mBlendFunc[1] =0;
+}
+
+void KX_BlenderMaterial::OnExit()
+{
+ if( mShader ) {
+ //note, the shader here is allocated, per unique material
+ //and this function is called per face
+ mShader->SetProg(0);
+ delete mShader;
+ mShader = 0;
+ }
+
+ BL_Texture::ActivateFirst();
+ for(int i=0; i<mMaterial->num_enabled; i++) {
+ BL_Texture::ActivateUnit(i);
+ mTextures[i].DeleteTex();
+ mTextures[i].DisableUnit();
+ }
+
+ if( mMaterial->tface )
+ set_tpage(mMaterial->tface);
+}
+
+
+void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras)
+{
+ MT_assert(RAS_EXT_support._ARB_shader_objects && mShader);
+
+ int i;
+ if( !enable || !mShader->Ok() ) {
+ // frame cleanup.
+ mShader->SetProg(false);
+ BL_Texture::DisableAllTextures();
+ return;
+ }
+
+ BL_Texture::DisableAllTextures();
+ mShader->SetProg(true);
+
+ BL_Texture::ActivateFirst();
+
+ mShader->ApplyShader();
+
+ // for each enabled unit
+ for(i=0; i<mMaterial->num_enabled; i++) {
+ if(!mTextures[i].Ok()) continue;
+ mTextures[i].ActivateTexture();
+ mTextures[0].SetMapping(mMaterial->mapping[i].mapping);
+ }
+
+ if(!mUserDefBlend) {
+ setDefaultBlending();
+ }
+ else {
+ // tested to be valid enums
+ glEnable(GL_BLEND);
+ glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
+ }
+}
+
+
+void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras)
+{
+ if(RAS_EXT_support._ARB_shader_objects && mShader)
+ mShader->SetProg(false);
+
+ BL_Texture::DisableAllTextures();
+ if( !enable )
+ return;
+
+ BL_Texture::ActivateFirst();
+
+ if( mMaterial->IdMode == DEFAULT_BLENDER ) {
+ setDefaultBlending();
+ return;
+ }
+
+ if( mMaterial->IdMode == TEXFACE ) {
+ // no material connected to the object
+ if( mTextures[0].Ok() ) {
+ mTextures[0].ActivateTexture();
+ mTextures[0].setTexEnv(0, true);
+ mTextures[0].SetMapping(mMaterial->mapping[0].mapping);
+ setDefaultBlending();
+ }
+ return;
+ }
+
+ int mode = 0,i=0;
+ for(i=0; (i<mMaterial->num_enabled && i<MAXTEX); i++) {
+ if( !mTextures[i].Ok() ) continue;
+
+ mTextures[i].ActivateTexture();
+ mTextures[i].setTexEnv(mMaterial);
+ mode = mMaterial->mapping[i].mapping;
+
+ if(mode &USEOBJ)
+ setObjectMatrixData(i, ras);
+ else
+ mTextures[i].SetMapping(mode);
+
+ if(!(mode &USEOBJ))
+ setTexMatrixData( i );
+ }
+
+ if(!mUserDefBlend) {
+ setDefaultBlending();
+ }
+ else {
+ glEnable(GL_BLEND);
+ glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
+ }
+}
+
+void
+KX_BlenderMaterial::ActivatShaders(
+ RAS_IRasterizer* rasty,
+ TCachingInfo& cachingInfo)const
+{
+ KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
+
+ // reset...
+ if(tmp->mMaterial->IsShared())
+ cachingInfo =0;
+
+ if (GetCachingInfo() != cachingInfo) {
+
+ if (!cachingInfo)
+ tmp->setShaderData( false, rasty);
+
+ cachingInfo = GetCachingInfo();
+
+ if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED ) {
+ tmp->setShaderData( true, rasty);
+ rasty->EnableTextures(true);
+ }
+ else {
+ tmp->setShaderData( false, rasty);
+ rasty->EnableTextures(false);
+ }
+
+ if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
+ rasty->SetCullFace(false);
+ else
+ rasty->SetCullFace(true);
+
+ if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES)
+ {
+ if((mMaterial->ras_mode &WIRE)!=0)
+ rasty->SetCullFace(false);
+ rasty->SetLines(true);
+ }
+ else
+ rasty->SetLines(false);
+ }
+
+ ActivatGLMaterials(rasty);
+ ActivateTexGen(rasty);
+}
+
+void
+KX_BlenderMaterial::ActivateMat(
+ RAS_IRasterizer* rasty,
+ TCachingInfo& cachingInfo
+ )const
+{
+ KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
+ if (GetCachingInfo() != cachingInfo) {
+ if (!cachingInfo)
+ tmp->setTexData( false,rasty );
+
+ cachingInfo = GetCachingInfo();
+
+ if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) {
+ tmp->setTexData( true,rasty );
+ rasty->EnableTextures(true);
+ }
+ else{
+ tmp->setTexData( false,rasty);
+ rasty->EnableTextures(false);
+ }
+
+ if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
+ rasty->SetCullFace(false);
+ else
+ rasty->SetCullFace(true);
+
+ if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES)
+ {
+ if((mMaterial->ras_mode &WIRE)!=0)
+ rasty->SetCullFace(false);
+ rasty->SetLines(true);
+ }
+ else
+ rasty->SetLines(false);
+ }
+ ActivatGLMaterials(rasty);
+ ActivateTexGen(rasty);
+}
+
+
+bool
+KX_BlenderMaterial::Activate(
+ RAS_IRasterizer* rasty,
+ TCachingInfo& cachingInfo
+ )const
+{
+ bool dopass = false;
+ if( RAS_EXT_support._ARB_shader_objects && ( mShader && mShader->Ok() ) ) {
+ if( (mPass++) < mShader->getNumPass() ) {
+ ActivatShaders(rasty, cachingInfo);
+ dopass = true;
+ return dopass;
+ }
+ else {
+ mShader->SetProg(false);
+ mPass = 0;
+ dopass = false;
+ return dopass;
+ }
+ }
+ else {
+ switch (mPass++)
+ {
+ case 0:
+ ActivateMat(rasty, cachingInfo);
+ dopass = true;
+ break;
+ default:
+ mPass = 0;
+ dopass = false;
+ break;
+ }
+ }
+ return dopass;
+}
+
+void KX_BlenderMaterial::ActivateMeshSlot(const KX_MeshSlot & ms, RAS_IRasterizer* rasty) const
+{
+ if(mShader && RAS_EXT_support._ARB_shader_objects)
+ mShader->Update(ms, rasty);
+}
+
+void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const
+{
+ rasty->SetSpecularity(
+ mMaterial->speccolor[0]*mMaterial->spec_f,
+ mMaterial->speccolor[1]*mMaterial->spec_f,
+ mMaterial->speccolor[2]*mMaterial->spec_f,
+ mMaterial->spec_f
+ );
+
+ rasty->SetShinyness( mMaterial->hard );
+
+ rasty->SetDiffuse(
+ mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit,
+ mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit,
+ mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit,
+ 1.0f);
+
+ rasty->SetEmissive(
+ mMaterial->matcolor[0]*mMaterial->emit,
+ mMaterial->matcolor[1]*mMaterial->emit,
+ mMaterial->matcolor[2]*mMaterial->emit,
+ 1.0 );
+
+ rasty->SetAmbient(mMaterial->amb);
+ if (mMaterial->material)
+ rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0);
+}
+
+
+void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const
+{
+ if(mShader && RAS_EXT_support._ARB_shader_objects)
+ if(mShader->GetAttribute() == BL_Shader::SHD_TANGENT)
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT);
+
+ for(int i=0; i<mMaterial->num_enabled; i++) {
+ int mode = mMaterial->mapping[i].mapping;
+
+ if (mode &USECUSTOMUV)
+ {
+ STR_String str = mMaterial->mapping[i].uvCoName;
+ if (!str.IsEmpty())
+ ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_UV2, i);
+ continue;
+ }
+
+ if( mode &(USEREFL|USEOBJ))
+ ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_GEN, i);
+ else if(mode &USEORCO)
+ ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_ORCO, i);
+ else if(mode &USENORM)
+ ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_NORM, i);
+ else if(mode &USEUV)
+ ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_UV1, i);
+ else if(mode &USETANG)
+ ras->SetTexCoords(RAS_IRasterizer::RAS_TEXTANGENT, i);
+ else
+ ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_DISABLE, i);
+ }
+}
+
+bool KX_BlenderMaterial::setDefaultBlending()
+{
+ if( mMaterial->transp &TF_ADD) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+ return true;
+ }
+
+ if( mMaterial->transp & TF_ALPHA ) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ return true;
+ }
+
+ glDisable(GL_BLEND);
+ return false;
+}
+
+void KX_BlenderMaterial::setTexMatrixData(int i)
+{
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+#ifdef GL_ARB_texture_cube_map
+ if( RAS_EXT_support._ARB_texture_cube_map &&
+ mTextures[i].GetTextureType() == GL_TEXTURE_CUBE_MAP_ARB &&
+ mMaterial->mapping[i].mapping & USEREFL) {
+ glScalef(
+ mMaterial->mapping[i].scale[0],
+ -mMaterial->mapping[i].scale[1],
+ -mMaterial->mapping[i].scale[2]
+ );
+ }
+ else
+#endif
+ {
+ glScalef(
+ mMaterial->mapping[i].scale[0],
+ mMaterial->mapping[i].scale[1],
+ mMaterial->mapping[i].scale[2]
+ );
+ }
+ glTranslatef(
+ mMaterial->mapping[i].offsets[0],
+ mMaterial->mapping[i].offsets[1],
+ mMaterial->mapping[i].offsets[2]
+ );
+
+ glMatrixMode(GL_MODELVIEW);
+
+}
+
+static void GetProjPlane(BL_Material *mat, int index,int num, float*param)
+{
+ param[0]=param[1]=param[2]=param[3]=0.f;
+ if( mat->mapping[index].projplane[num] == PROJX )
+ param[0] = 1.f;
+ else if( mat->mapping[index].projplane[num] == PROJY )
+ param[1] = 1.f;
+ else if( mat->mapping[index].projplane[num] == PROJZ)
+ param[2] = 1.f;
+}
+
+void KX_BlenderMaterial::setObjectMatrixData(int i, RAS_IRasterizer *ras)
+{
+ KX_GameObject *obj =
+ (KX_GameObject*)
+ mScene->GetObjectList()->FindValue(mMaterial->mapping[i].objconame);
+
+ if(!obj) return;
+
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
+ glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
+
+ GLenum plane = GL_EYE_PLANE;
+
+ // figure plane gen
+ float proj[4]= {0.f,0.f,0.f,0.f};
+ GetProjPlane(mMaterial, i, 0, proj);
+ glTexGenfv(GL_S, plane, proj);
+
+ GetProjPlane(mMaterial, i, 1, proj);
+ glTexGenfv(GL_T, plane, proj);
+
+ GetProjPlane(mMaterial, i, 2, proj);
+ glTexGenfv(GL_R, plane, proj);
+
+ glEnable(GL_TEXTURE_GEN_S);
+ glEnable(GL_TEXTURE_GEN_T);
+ glEnable(GL_TEXTURE_GEN_R);
+
+ MT_Matrix4x4 mvmat;
+ ras->GetViewMatrix(mvmat);
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glScalef(
+ mMaterial->mapping[i].scale[0],
+ mMaterial->mapping[i].scale[1],
+ mMaterial->mapping[i].scale[2]
+ );
+
+ MT_Point3 pos = obj->NodeGetWorldPosition();
+ MT_Vector4 matmul = MT_Vector4(pos[0], pos[1], pos[2], 1.f);
+ MT_Vector4 t = mvmat*matmul;
+
+ glTranslatef( (float)(-t[0]), (float)(-t[1]), (float)(-t[2]) );
+
+ glMatrixMode(GL_MODELVIEW);
+
+}
+
+// ------------------------------------
+void KX_BlenderMaterial::UpdateIPO(
+ MT_Vector4 rgba,
+ MT_Vector3 specrgb,
+ MT_Scalar hard,
+ MT_Scalar spec,
+ MT_Scalar ref,
+ MT_Scalar emit,
+ MT_Scalar alpha
+ )
+{
+ // only works one deep now
+ mMaterial->speccolor[0] = (float)(specrgb)[0];
+ mMaterial->speccolor[1] = (float)(specrgb)[1];
+ mMaterial->speccolor[2] = (float)(specrgb)[2];
+ mMaterial->matcolor[0] = (float)(rgba[0]);
+ mMaterial->matcolor[1] = (float)(rgba[1]);
+ mMaterial->matcolor[2] = (float)(rgba[2]);
+ mMaterial->alpha = (float)(alpha);
+ mMaterial->hard = (float)(hard);
+ mMaterial->emit = (float)(emit);
+ mMaterial->spec_f = (float)(spec);
+}
+
+
+PyMethodDef KX_BlenderMaterial::Methods[] =
+{
+ KX_PYMETHODTABLE( KX_BlenderMaterial, getShader ),
+ KX_PYMETHODTABLE( KX_BlenderMaterial, getMaterialIndex ),
+ KX_PYMETHODTABLE( KX_BlenderMaterial, setBlending ),
+ {NULL,NULL} //Sentinel
+};
+
+
+PyTypeObject KX_BlenderMaterial::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_BlenderMaterial",
+ sizeof(KX_BlenderMaterial),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0,
+ __repr,
+ 0
+};
+
+
+PyParentObject KX_BlenderMaterial::Parents[] = {
+ &PyObjectPlus::Type,
+ &KX_BlenderMaterial::Type,
+ NULL
+};
+
+
+PyObject* KX_BlenderMaterial::_getattr(const STR_String& attr)
+{
+ _getattr_up(PyObjectPlus);
+}
+
+int KX_BlenderMaterial::_setattr(const STR_String& attr, PyObject *pyvalue)
+{
+ return PyObjectPlus::_setattr(attr, pyvalue);
+}
+
+
+KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()")
+{
+#ifdef GL_ARB_fragment_shader
+ if( !RAS_EXT_support._ARB_fragment_shader) {
+ if(!mModified)
+ spit("Fragment shaders not supported");
+
+ mModified = true;
+ Py_Return;
+ }
+#endif
+
+#ifdef GL_ARB_vertex_shader
+ if( !RAS_EXT_support._ARB_vertex_shader) {
+ if(!mModified)
+ spit("Vertex shaders not supported");
+
+ mModified = true;
+ Py_Return;
+ }
+#endif
+
+#ifdef GL_ARB_shader_objects
+ if(!RAS_EXT_support._ARB_shader_objects) {
+ if(!mModified)
+ spit("GLSL not supported");
+ mModified = true;
+ Py_Return;
+ }
+ else {
+ // returns Py_None on error
+ // the calling script will need to check
+
+ if(!mShader && !mModified) {
+ mShader = new BL_Shader();
+ mModified = true;
+ }
+
+ if(mShader && !mShader->GetError()) {
+ mMaterial->SetSharedMaterial(true);
+ Py_INCREF(mShader);
+ return mShader;
+ }else
+ {
+ // decref all references to the object
+ // then delete it!
+ // We will then go back to fixed functionality
+ // for this material
+ if(mShader) {
+ if(mShader->ob_refcnt > 1) {
+ Py_DECREF(mShader);
+ }
+ else {
+ delete mShader;
+ mShader=0;
+ }
+ }
+ }
+ Py_Return;
+ }
+ PyErr_Format(PyExc_ValueError, "GLSL Error");
+ return NULL;
+
+#else
+ Py_Return;
+#endif//GL_ARB_shader_objects
+}
+
+
+KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()")
+{
+ return PyInt_FromLong( mMaterial->material_index );
+}
+
+KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getTexture, "getTexture( index )" )
+{
+ // TODO: enable python switching
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setTexture , "setTexture( index, tex)")
+{
+ // TODO: enable python switching
+ return NULL;
+}
+
+static unsigned int GL_array[11] = {
+ GL_ZERO,
+ GL_ONE,
+ GL_SRC_COLOR,
+ GL_ONE_MINUS_SRC_COLOR,
+ GL_DST_COLOR,
+ GL_ONE_MINUS_DST_COLOR,
+ GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA,
+ GL_DST_ALPHA,
+ GL_ONE_MINUS_DST_ALPHA,
+ GL_SRC_ALPHA_SATURATE
+};
+
+KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setBlending , "setBlending( GameLogic.src, GameLogic.dest)")
+{
+ unsigned int b[2];
+ if(PyArg_ParseTuple(args, "ii", &b[0], &b[1]))
+ {
+ bool value_found[2] = {false, false};
+ for(int i=0; i<11; i++)
+ {
+ if(b[0] == GL_array[i]) {
+ value_found[0] = true;
+ mBlendFunc[0] = b[0];
+ }
+ if(b[1] == GL_array[i]) {
+ value_found[1] = true;
+ mBlendFunc[1] = b[1];
+ }
+ if(value_found[0] && value_found[1]) break;
+ }
+ if(!value_found[0] || !value_found[1]) {
+ PyErr_Format(PyExc_ValueError, "invalid enum.");
+ return NULL;
+ }
+ mUserDefBlend = true;
+ Py_Return;
+ }
+ return NULL;
+}
+
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h
new file mode 100644
index 00000000000..2b1264154d0
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h
@@ -0,0 +1,118 @@
+#ifndef __KX_BLENDER_MATERIAL_H__
+#define __KX_BLENDER_MATERIAL_H__
+
+#include <vector>
+
+
+#include "RAS_IPolygonMaterial.h"
+#include "BL_Material.h"
+#include "BL_Texture.h"
+#include "BL_Shader.h"
+
+#include "PyObjectPlus.h"
+
+#include "MT_Vector3.h"
+#include "MT_Vector4.h"
+
+struct MTFace;
+class KX_Scene;
+
+class KX_BlenderMaterial : public PyObjectPlus, public RAS_IPolyMaterial
+{
+ Py_Header;
+public:
+ // --------------------------------
+ KX_BlenderMaterial(
+ class KX_Scene* scene,
+ BL_Material* mat,
+ bool skin,
+ int lightlayer,
+ void* clientobject,
+ PyTypeObject* T=&Type
+ );
+
+ virtual ~KX_BlenderMaterial();
+
+ // --------------------------------
+ virtual TCachingInfo GetCachingInfo(void) const {
+ return (void*) this;
+ }
+
+ virtual
+ bool Activate(
+ RAS_IRasterizer* rasty,
+ TCachingInfo& cachingInfo
+ ) const;
+
+ virtual
+ void ActivateMeshSlot(
+ const KX_MeshSlot & ms,
+ RAS_IRasterizer* rasty
+ ) const;
+
+ void ActivateMat(
+ RAS_IRasterizer* rasty,
+ TCachingInfo& cachingInfo
+ )const;
+
+ void ActivatShaders(
+ RAS_IRasterizer* rasty,
+ TCachingInfo& cachingInfo
+ )const;
+
+
+ MTFace* GetMTFace(void) const;
+ unsigned int* GetMCol(void) const;
+
+ // for ipos
+ void UpdateIPO(
+ MT_Vector4 rgba, MT_Vector3 specrgb,
+ MT_Scalar hard, MT_Scalar spec,
+ MT_Scalar ref, MT_Scalar emit, MT_Scalar alpha
+ );
+
+ // --------------------------------
+ virtual PyObject* _getattr(const STR_String& attr);
+ virtual int _setattr(const STR_String& attr, PyObject *pyvalue);
+
+ KX_PYMETHOD_DOC( KX_BlenderMaterial, getShader );
+ KX_PYMETHOD_DOC( KX_BlenderMaterial, getMaterialIndex );
+ KX_PYMETHOD_DOC( KX_BlenderMaterial, getTexture );
+ KX_PYMETHOD_DOC( KX_BlenderMaterial, setTexture );
+
+ KX_PYMETHOD_DOC( KX_BlenderMaterial, setBlending );
+
+ // --------------------------------
+ // pre calculate to avoid pops/lag at startup
+ virtual void OnConstruction( );
+private:
+ BL_Material* mMaterial;
+ BL_Shader* mShader;
+ KX_Scene* mScene;
+ BL_Texture mTextures[MAXTEX]; // texture array
+ bool mUserDefBlend;
+ unsigned int mBlendFunc[2];
+ bool mModified;
+
+ void ActivatGLMaterials( RAS_IRasterizer* rasty )const;
+ void ActivateTexGen( RAS_IRasterizer *ras ) const;
+
+
+ // message centers
+ void setTexData( bool enable,RAS_IRasterizer *ras);
+ void setShaderData( bool enable, RAS_IRasterizer *ras);
+
+ bool setDefaultBlending();
+ void setObjectMatrixData(int i, RAS_IRasterizer *ras);
+ void setTexMatrixData(int i);
+
+ void setLightData();
+
+ // cleanup stuff
+ void OnExit();
+
+ mutable int mPass;
+};
+
+
+#endif
diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp
new file mode 100644
index 00000000000..aa5d1f1cec1
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp
@@ -0,0 +1,247 @@
+//under visual studio the #define in KX_ConvertPhysicsObject.h is quicker for recompilation
+#include "KX_ConvertPhysicsObject.h"
+
+#ifdef USE_BULLET
+
+#include "KX_BulletPhysicsController.h"
+
+#include "btBulletDynamicsCommon.h"
+#include "SG_Spatial.h"
+
+#include "KX_GameObject.h"
+#include "KX_MotionState.h"
+#include "KX_ClientObjectInfo.h"
+
+#include "PHY_IPhysicsEnvironment.h"
+
+
+KX_BulletPhysicsController::KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna)
+: KX_IPhysicsController(dyna,(PHY_IPhysicsController*)this),
+CcdPhysicsController(ci)
+{
+
+}
+
+KX_BulletPhysicsController::~KX_BulletPhysicsController ()
+{
+
+}
+
+void KX_BulletPhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ)
+{
+ CcdPhysicsController::resolveCombinedVelocities(linvelX,linvelY,linvelZ,angVelX,angVelY,angVelZ);
+
+}
+
+
+ ///////////////////////////////////
+ // KX_IPhysicsController interface
+ ////////////////////////////////////
+
+void KX_BulletPhysicsController::applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse)
+{
+ CcdPhysicsController::applyImpulse(attach[0],attach[1],attach[2],impulse[0],impulse[1],impulse[2]);
+
+}
+
+void KX_BulletPhysicsController::SetObject (SG_IObject* object)
+{
+ SG_Controller::SetObject(object);
+
+ // cheating here...
+ //should not be necessary, is it for duplicates ?
+
+ KX_GameObject* gameobj = (KX_GameObject*) object->GetSGClientObject();
+ gameobj->SetPhysicsController(this,gameobj->IsDynamic());
+ CcdPhysicsController::setNewClientInfo(gameobj->getClientInfo());
+
+
+}
+
+void KX_BulletPhysicsController::setMargin (float collisionMargin)
+{
+ CcdPhysicsController::SetMargin(collisionMargin);
+}
+void KX_BulletPhysicsController::RelativeTranslate(const MT_Vector3& dloc,bool local)
+{
+ CcdPhysicsController::RelativeTranslate(dloc[0],dloc[1],dloc[2],local);
+
+}
+
+void KX_BulletPhysicsController::RelativeRotate(const MT_Matrix3x3& drot,bool local)
+{
+ float rotval[12];
+ drot.getValue(rotval);
+ CcdPhysicsController::RelativeRotate(rotval,local);
+}
+
+void KX_BulletPhysicsController::ApplyTorque(const MT_Vector3& torque,bool local)
+{
+ CcdPhysicsController::ApplyTorque(torque.x(),torque.y(),torque.z(),local);
+}
+void KX_BulletPhysicsController::ApplyForce(const MT_Vector3& force,bool local)
+{
+ CcdPhysicsController::ApplyForce(force.x(),force.y(),force.z(),local);
+}
+MT_Vector3 KX_BulletPhysicsController::GetLinearVelocity()
+{
+ float angVel[3];
+ //CcdPhysicsController::GetAngularVelocity(angVel[0],angVel[1],angVel[2]);
+ CcdPhysicsController::GetLinearVelocity(angVel[0],angVel[1],angVel[2]);//rcruiz
+ return MT_Vector3(angVel[0],angVel[1],angVel[2]);
+}
+MT_Vector3 KX_BulletPhysicsController::GetVelocity(const MT_Point3& pos)
+{
+ float linVel[3];
+ CcdPhysicsController::GetLinearVelocity(linVel[0],linVel[1],linVel[2]);
+ return MT_Vector3(linVel[0],linVel[1],linVel[2]);
+}
+
+void KX_BulletPhysicsController::SetAngularVelocity(const MT_Vector3& ang_vel,bool local)
+{
+ CcdPhysicsController::SetAngularVelocity(ang_vel.x(),ang_vel.y(),ang_vel.z(),local);
+
+}
+void KX_BulletPhysicsController::SetLinearVelocity(const MT_Vector3& lin_vel,bool local)
+{
+ CcdPhysicsController::SetLinearVelocity(lin_vel.x(),lin_vel.y(),lin_vel.z(),local);
+}
+void KX_BulletPhysicsController::getOrientation(MT_Quaternion& orn)
+{
+ float myorn[4];
+ CcdPhysicsController::getOrientation(myorn[0],myorn[1],myorn[2],myorn[3]);
+ orn = MT_Quaternion(myorn[0],myorn[1],myorn[2],myorn[3]);
+}
+void KX_BulletPhysicsController::setOrientation(const MT_Quaternion& orn)
+{
+ CcdPhysicsController::setOrientation(orn.x(),orn.y(),orn.z(),orn.w());
+}
+void KX_BulletPhysicsController::setPosition(const MT_Point3& pos)
+{
+ CcdPhysicsController::setPosition(pos.x(),pos.y(),pos.z());
+}
+void KX_BulletPhysicsController::setScaling(const MT_Vector3& scaling)
+{
+ CcdPhysicsController::setScaling(scaling.x(),scaling.y(),scaling.z());
+}
+MT_Scalar KX_BulletPhysicsController::GetMass()
+{
+
+ MT_Scalar invmass = GetRigidBody()->getInvMass();
+ if (invmass)
+ return 1.f/invmass;
+ return 0.f;
+
+}
+MT_Vector3 KX_BulletPhysicsController::getReactionForce()
+{
+ assert(0);
+ return MT_Vector3(0.f,0.f,0.f);
+}
+void KX_BulletPhysicsController::setRigidBody(bool rigid)
+{
+}
+
+void KX_BulletPhysicsController::SuspendDynamics()
+{
+ GetRigidBody()->setActivationState(DISABLE_SIMULATION);
+
+}
+void KX_BulletPhysicsController::RestoreDynamics()
+{
+ GetRigidBody()->forceActivationState(ACTIVE_TAG);
+}
+
+SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode)
+{
+ PHY_IMotionState* motionstate = new KX_MotionState(destnode);
+
+ KX_BulletPhysicsController* physicsreplica = new KX_BulletPhysicsController(*this);
+
+ //parentcontroller is here be able to avoid collisions between parent/child
+
+ PHY_IPhysicsController* parentctrl = NULL;
+
+ if (destnode != destnode->GetRootSGParent())
+ {
+ KX_GameObject* clientgameobj = (KX_GameObject*) destnode->GetRootSGParent()->GetSGClientObject();
+ if (clientgameobj)
+ {
+ parentctrl = (KX_BulletPhysicsController*)clientgameobj->GetPhysicsController();
+ } else
+ {
+ // it could be a false node, try the children
+ NodeList::const_iterator childit;
+ for (
+ childit = destnode->GetSGChildren().begin();
+ childit!= destnode->GetSGChildren().end();
+ ++childit
+ ) {
+ KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject());
+ if (clientgameobj)
+ {
+ parentctrl = (KX_BulletPhysicsController*)clientgameobj->GetPhysicsController();
+ }
+ }
+ }
+ }
+
+ physicsreplica->PostProcessReplica(motionstate,parentctrl);
+ physicsreplica->m_userdata = (PHY_IPhysicsController*)physicsreplica;
+ return physicsreplica;
+
+}
+
+
+
+void KX_BulletPhysicsController::SetSumoTransform(bool nondynaonly)
+{
+ GetRigidBody()->activate(true);
+
+ if (!m_bDyna)
+ {
+ GetRigidBody()->setCollisionFlags(GetRigidBody()->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
+ } else
+ {
+ if (!nondynaonly)
+ {
+ btTransform worldTrans;
+ GetRigidBody()->getMotionState()->getWorldTransform(worldTrans);
+ GetRigidBody()->setCenterOfMassTransform(worldTrans);
+
+ /*
+ scaling?
+ if (m_bDyna)
+ {
+ m_sumoObj->setScaling(MT_Vector3(1,1,1));
+ } else
+ {
+ MT_Vector3 scale;
+ GetWorldScaling(scale);
+ m_sumoObj->setScaling(scale);
+ }
+ */
+
+ }
+ }
+}
+
+// todo: remove next line !
+void KX_BulletPhysicsController::SetSimulatedTime(double time)
+{
+}
+
+// call from scene graph to update
+bool KX_BulletPhysicsController::Update(double time)
+{
+ return false;
+
+ // todo: check this code
+ //if (GetMass())
+ //{
+ // return false;//true;
+// }
+// return false;
+}
+
+#endif //#ifdef USE_BULLET
diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.h b/source/gameengine/Ketsji/KX_BulletPhysicsController.h
new file mode 100644
index 00000000000..619ac42503f
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.h
@@ -0,0 +1,70 @@
+#ifndef KX_BULLET2PHYSICS_CONTROLLER
+#define KX_BULLET2PHYSICS_CONTROLLER
+
+
+#include "KX_IPhysicsController.h"
+#include "CcdPhysicsController.h"
+
+class KX_BulletPhysicsController : public KX_IPhysicsController ,public CcdPhysicsController
+{
+
+public:
+
+ KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna);
+ virtual ~KX_BulletPhysicsController ();
+
+ ///////////////////////////////////
+ // KX_IPhysicsController interface
+ ////////////////////////////////////
+
+ virtual void applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse);
+ virtual void SetObject (SG_IObject* object);
+ virtual void setMargin (float collisionMargin);
+ virtual void RelativeTranslate(const MT_Vector3& dloc,bool local);
+ virtual void RelativeRotate(const MT_Matrix3x3& drot,bool local);
+ virtual void ApplyTorque(const MT_Vector3& torque,bool local);
+ virtual void ApplyForce(const MT_Vector3& force,bool local);
+ virtual MT_Vector3 GetLinearVelocity();
+ virtual MT_Vector3 GetVelocity(const MT_Point3& pos);
+ virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local);
+ virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local);
+ virtual void getOrientation(MT_Quaternion& orn);
+ virtual void setOrientation(const MT_Quaternion& orn);
+ virtual void setPosition(const MT_Point3& pos);
+ virtual void setScaling(const MT_Vector3& scaling);
+ virtual MT_Scalar GetMass();
+ virtual MT_Vector3 getReactionForce();
+ virtual void setRigidBody(bool rigid);
+
+ virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ);
+
+ virtual void SuspendDynamics();
+ virtual void RestoreDynamics();
+
+ virtual SG_Controller* GetReplica(class SG_Node* destnode);
+
+ void SetDyna(bool isDynamic) {
+ m_bDyna = isDynamic;
+ }
+
+
+ virtual void SetSumoTransform(bool nondynaonly);
+ // todo: remove next line !
+ virtual void SetSimulatedTime(double time);
+
+ // call from scene graph to update
+ virtual bool Update(double time);
+ void* GetUserData() { return m_userdata;}
+
+ void
+ SetOption(
+ int option,
+ int value
+ ){
+ // intentionally empty
+ };
+
+};
+
+#endif //KX_BULLET2PHYSICS_CONTROLLER
+
diff --git a/source/gameengine/Ketsji/KX_CDActuator.cpp b/source/gameengine/Ketsji/KX_CDActuator.cpp
new file mode 100644
index 00000000000..b4a7763763a
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_CDActuator.cpp
@@ -0,0 +1,256 @@
+/**
+ * KX_CDActuator.cpp
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_CDActuator.h"
+#include "SND_CDObject.h"
+#include "KX_GameObject.h"
+#include "SND_Scene.h" // needed for replication
+#include <iostream>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+KX_CDActuator::KX_CDActuator(SCA_IObject* gameobject,
+ SND_Scene* soundscene,
+ KX_CDACT_TYPE type,
+ int track,
+ short start,
+ short end,
+ PyTypeObject* T)
+ : SCA_IActuator(gameobject,T)
+{
+ m_soundscene = soundscene;
+ m_type = type;
+ m_track = track;
+ m_lastEvent = true;
+ m_isplaying = false;
+ m_startFrame = start;
+ m_endFrame = end;
+ m_gain = SND_CDObject::Instance()->GetGain();
+}
+
+
+
+KX_CDActuator::~KX_CDActuator()
+{
+}
+
+
+/* hmmm, do we want this? */
+CValue* KX_CDActuator::GetReplica()
+{
+ KX_CDActuator* replica = new KX_CDActuator(*this);
+ replica->ProcessReplica();
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+};
+
+
+
+bool KX_CDActuator::Update()
+{
+ bool result = false;
+ bool bNegativeEvent = IsNegativeEvent();
+
+ RemoveAllEvents();
+
+ if (!bNegativeEvent)
+ {
+ switch (m_type)
+ {
+ case KX_CDACT_PLAY_ALL:
+ {
+ SND_CDObject::Instance()->SetPlaymode(SND_CD_ALL);
+ SND_CDObject::Instance()->SetTrack(1);
+ SND_CDObject::Instance()->SetPlaystate(SND_MUST_PLAY);
+ result = true;
+ break;
+ }
+ case KX_CDACT_PLAY_TRACK:
+ {
+ SND_CDObject::Instance()->SetPlaymode(SND_CD_TRACK);
+ SND_CDObject::Instance()->SetTrack(m_track);
+ SND_CDObject::Instance()->SetPlaystate(SND_MUST_PLAY);
+ result = true;
+ break;
+ }
+ case KX_CDACT_LOOP_TRACK:
+ {
+ SND_CDObject::Instance()->SetPlaymode(SND_CD_ALL);
+ SND_CDObject::Instance()->SetTrack(m_track);
+ SND_CDObject::Instance()->SetPlaystate(SND_MUST_PLAY);
+ result = true;
+ break;
+ }
+ case KX_CDACT_STOP:
+ {
+ SND_CDObject::Instance()->SetPlaystate(SND_MUST_STOP);
+ break;
+ }
+ case KX_CDACT_PAUSE:
+ {
+ SND_CDObject::Instance()->SetPlaystate(SND_MUST_PAUSE);
+ result = true;
+ break;
+ }
+ case KX_CDACT_RESUME:
+ {
+ SND_CDObject::Instance()->SetPlaystate(SND_MUST_RESUME);
+ result = true;
+ break;
+ }
+ case KX_CDACT_VOLUME:
+ {
+ SND_CDObject::Instance()->SetGain(m_gain);
+ result = true;
+ break;
+ }
+ default:
+ // implement me !!
+ break;
+ }
+ }
+ return result;
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_CDActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_SoundActuator",
+ sizeof(KX_CDActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+
+PyParentObject KX_CDActuator::Parents[] = {
+ &KX_CDActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+PyMethodDef KX_CDActuator::Methods[] = {
+ {"startCD",(PyCFunction) KX_CDActuator::sPyStartCD,METH_VARARGS,NULL},
+ {"pauseCD",(PyCFunction) KX_CDActuator::sPyPauseCD,METH_VARARGS,NULL},
+ {"stopCD",(PyCFunction) KX_CDActuator::sPyStopCD,METH_VARARGS,NULL},
+ {"setGain",(PyCFunction) KX_CDActuator::sPySetGain,METH_VARARGS,NULL},
+ {"getGain",(PyCFunction) KX_CDActuator::sPyGetGain,METH_VARARGS,NULL},
+ {NULL,NULL,NULL,NULL} //Sentinel
+};
+
+
+
+PyObject* KX_CDActuator::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_IActuator);
+}
+
+
+
+
+PyObject* KX_CDActuator::PyStartCD(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ SND_CDObject::Instance()->SetPlaystate(SND_MUST_PLAY);
+ Py_Return;
+}
+
+
+
+PyObject* KX_CDActuator::PyPauseCD(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ SND_CDObject::Instance()->SetPlaystate(SND_MUST_PAUSE);
+ Py_Return;
+}
+
+
+
+PyObject* KX_CDActuator::PyStopCD(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ SND_CDObject::Instance()->SetPlaystate(SND_MUST_STOP);
+ Py_Return;
+}
+
+
+
+PyObject* KX_CDActuator::PySetGain(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ float gain = 1.0;
+ if (!PyArg_ParseTuple(args, "f", &gain))
+ return NULL;
+
+ SND_CDObject::Instance()->SetGain(gain);
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_CDActuator::PyGetGain(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ float gain = SND_CDObject::Instance()->GetGain();
+ PyObject* result = PyFloat_FromDouble(gain);
+
+ return result;
+}
diff --git a/source/gameengine/Ketsji/KX_CDActuator.h b/source/gameengine/Ketsji/KX_CDActuator.h
new file mode 100644
index 00000000000..db6dc1e3475
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_CDActuator.h
@@ -0,0 +1,97 @@
+/**
+ * KX_CDActuator.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 __KX_CDACTUATOR
+#define __KX_CDACTUATOR
+
+#include "SCA_IActuator.h"
+#include "SND_CDObject.h"
+
+class KX_CDActuator : public SCA_IActuator
+{
+ Py_Header;
+ bool m_lastEvent;
+ bool m_isplaying;
+ /* just some handles to the audio-data... */
+ class SND_Scene* m_soundscene;
+ int m_track;
+ float m_gain;
+ short m_startFrame;
+ short m_endFrame;
+
+public:
+ enum KX_CDACT_TYPE
+ {
+ KX_CDACT_NODEF = 0,
+ KX_CDACT_PLAY_ALL,
+ KX_CDACT_PLAY_TRACK,
+ KX_CDACT_LOOP_TRACK,
+ KX_CDACT_VOLUME,
+ KX_CDACT_STOP,
+ KX_CDACT_PAUSE,
+ KX_CDACT_RESUME,
+ KX_SOUNDACT_MAX
+ };
+
+ KX_CDACT_TYPE m_type;
+
+ KX_CDActuator(SCA_IObject* gameobject,
+ SND_Scene* soundscene,
+ KX_CDACT_TYPE type,
+ int track,
+ short start,
+ short end,
+ PyTypeObject* T=&Type);
+
+ ~KX_CDActuator();
+
+ virtual bool Update();
+
+ CValue* GetReplica();
+
+ /* -------------------------------------------------------------------- */
+ /* Python interface --------------------------------------------------- */
+ /* -------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ KX_PYMETHOD(KX_CDActuator,StartCD);
+ KX_PYMETHOD(KX_CDActuator,PauseCD);
+ KX_PYMETHOD(KX_CDActuator,StopCD);
+ KX_PYMETHOD(KX_CDActuator,SetGain);
+ KX_PYMETHOD(KX_CDActuator,GetGain);
+};
+
+#endif //__KX_CDACTUATOR
+
diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp
new file mode 100644
index 00000000000..011443054a7
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_Camera.cpp
@@ -0,0 +1,761 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Camera in the gameengine. Cameras are also used for views.
+ */
+
+#include "KX_Camera.h"
+
+#include "KX_Python.h"
+#include "KX_PyMath.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_Camera::KX_Camera(void* sgReplicationInfo,
+ SG_Callbacks callbacks,
+ const RAS_CameraData& camdata,
+ bool frustum_culling,
+ PyTypeObject *T)
+ :
+ KX_GameObject(sgReplicationInfo,callbacks,T),
+ m_camdata(camdata),
+ m_dirty(true),
+ m_normalized(false),
+ m_frustum_culling(frustum_culling && camdata.m_perspective),
+ m_set_projection_matrix(false),
+ m_set_frustum_center(false)
+{
+ // setting a name would be nice...
+ m_name = "cam";
+ m_projection_matrix.setIdentity();
+ m_modelview_matrix.setIdentity();
+ SetProperty("camera",new CIntValue(1));
+}
+
+
+KX_Camera::~KX_Camera()
+{
+}
+
+
+
+MT_Transform KX_Camera::GetWorldToCamera() const
+{
+ MT_Transform camtrans;
+ camtrans.invert(MT_Transform(NodeGetWorldPosition(), NodeGetWorldOrientation()));
+
+ return camtrans;
+}
+
+
+
+MT_Transform KX_Camera::GetCameraToWorld() const
+{
+ return MT_Transform(NodeGetWorldPosition(), NodeGetWorldOrientation());
+}
+
+
+
+void KX_Camera::CorrectLookUp(MT_Scalar speed)
+{
+}
+
+
+
+const MT_Point3 KX_Camera::GetCameraLocation() const
+{
+ /* this is the camera locatio in cam coords... */
+ //return m_trans1.getOrigin();
+ //return MT_Point3(0,0,0); <-----
+ /* .... I want it in world coords */
+ //MT_Transform trans;
+ //trans.setBasis(NodeGetWorldOrientation());
+
+ return NodeGetWorldPosition();
+}
+
+
+
+/* I want the camera orientation as well. */
+const MT_Quaternion KX_Camera::GetCameraOrientation() const
+{
+ return NodeGetWorldOrientation().getRotation();
+}
+
+
+
+/**
+* Sets the projection matrix that is used by the rasterizer.
+*/
+void KX_Camera::SetProjectionMatrix(const MT_Matrix4x4 & mat)
+{
+ m_projection_matrix = mat;
+ m_dirty = true;
+ m_set_projection_matrix = true;
+ m_set_frustum_center = false;
+}
+
+
+
+/**
+* Sets the modelview matrix that is used by the rasterizer.
+*/
+void KX_Camera::SetModelviewMatrix(const MT_Matrix4x4 & mat)
+{
+ m_modelview_matrix = mat;
+ m_dirty = true;
+ m_set_frustum_center = false;
+}
+
+
+
+/**
+* Gets the projection matrix that is used by the rasterizer.
+*/
+const MT_Matrix4x4& KX_Camera::GetProjectionMatrix() const
+{
+ return m_projection_matrix;
+}
+
+
+
+/**
+* Gets the modelview matrix that is used by the rasterizer.
+*/
+const MT_Matrix4x4& KX_Camera::GetModelviewMatrix() const
+{
+ return m_modelview_matrix;
+}
+
+
+bool KX_Camera::hasValidProjectionMatrix() const
+{
+ return m_set_projection_matrix;
+}
+
+void KX_Camera::InvalidateProjectionMatrix(bool valid)
+{
+ m_set_projection_matrix = valid;
+}
+
+
+/*
+* These getters retrieve the clip data and the focal length
+*/
+float KX_Camera::GetLens() const
+{
+ return m_camdata.m_lens;
+}
+
+
+
+float KX_Camera::GetCameraNear() const
+{
+ return m_camdata.m_clipstart;
+}
+
+
+
+float KX_Camera::GetCameraFar() const
+{
+ return m_camdata.m_clipend;
+}
+
+
+
+RAS_CameraData* KX_Camera::GetCameraData()
+{
+ return &m_camdata;
+}
+
+void KX_Camera::ExtractClipPlanes()
+{
+ if (!m_dirty)
+ return;
+
+ MT_Matrix4x4 m = m_projection_matrix * m_modelview_matrix;
+ // Left clip plane
+ m_planes[0] = m[3] + m[0];
+ // Right clip plane
+ m_planes[1] = m[3] - m[0];
+ // Top clip plane
+ m_planes[2] = m[3] - m[1];
+ // Bottom clip plane
+ m_planes[3] = m[3] + m[1];
+ // Near clip plane
+ m_planes[4] = m[3] + m[2];
+ // Far clip plane
+ m_planes[5] = m[3] - m[2];
+
+ m_dirty = false;
+ m_normalized = false;
+}
+
+void KX_Camera::NormalizeClipPlanes()
+{
+ if (m_normalized)
+ return;
+
+ for (unsigned int p = 0; p < 6; p++)
+ {
+ MT_Scalar factor = sqrt(m_planes[p][0]*m_planes[p][0] + m_planes[p][1]*m_planes[p][1] + m_planes[p][2]*m_planes[p][2]);
+ if (!MT_fuzzyZero(factor))
+ m_planes[p] /= factor;
+ }
+
+ m_normalized = true;
+}
+
+void KX_Camera::ExtractFrustumSphere()
+{
+ if (m_set_frustum_center)
+ return;
+
+ // The most extreme points on the near and far plane. (normalized device coords)
+ MT_Vector4 hnear(1., 1., 0., 1.), hfar(1., 1., 1., 1.);
+ MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix;
+ clip_camcs_matrix.invert();
+
+ // Transform to hom camera local space
+ hnear = clip_camcs_matrix*hnear;
+ hfar = clip_camcs_matrix*hfar;
+
+ // Tranform to 3d camera local space.
+ MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]);
+ MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]);
+
+ // Compute center
+ m_frustum_center = MT_Point3(0., 0.,
+ (nearpoint.dot(nearpoint) - farpoint.dot(farpoint))/(2.0*(m_camdata.m_clipend - m_camdata.m_clipstart)));
+ m_frustum_radius = m_frustum_center.distance(farpoint);
+
+ // Transform to world space.
+ m_frustum_center = GetCameraToWorld()(m_frustum_center);
+ m_frustum_radius /= fabs(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]);
+
+ m_set_frustum_center = true;
+}
+
+bool KX_Camera::PointInsideFrustum(const MT_Point3& x)
+{
+ ExtractClipPlanes();
+
+ for( unsigned int i = 0; i < 6 ; i++ )
+ {
+ if (m_planes[i][0]*x[0] + m_planes[i][1]*x[1] + m_planes[i][2]*x[2] + m_planes[i][3] < 0.)
+ return false;
+ }
+ return true;
+}
+
+int KX_Camera::BoxInsideFrustum(const MT_Point3 *box)
+{
+ ExtractClipPlanes();
+
+ unsigned int insideCount = 0;
+ // 6 view frustum planes
+ for( unsigned int p = 0; p < 6 ; p++ )
+ {
+ unsigned int behindCount = 0;
+ // 8 box verticies.
+ for (unsigned int v = 0; v < 8 ; v++)
+ {
+ if (m_planes[p][0]*box[v][0] + m_planes[p][1]*box[v][1] + m_planes[p][2]*box[v][2] + m_planes[p][3] < 0.)
+ behindCount++;
+ }
+
+ // 8 points behind this plane
+ if (behindCount == 8)
+ return OUTSIDE;
+
+ // Every box vertex is on the front side of this plane
+ if (!behindCount)
+ insideCount++;
+ }
+
+ // All box verticies are on the front side of all frustum planes.
+ if (insideCount == 6)
+ return INSIDE;
+
+ return INTERSECT;
+}
+
+int KX_Camera::SphereInsideFrustum(const MT_Point3& center, const MT_Scalar &radius)
+{
+ ExtractFrustumSphere();
+ if (center.distance2(m_frustum_center) > (radius + m_frustum_radius)*(radius + m_frustum_radius))
+ return OUTSIDE;
+
+ unsigned int p;
+ ExtractClipPlanes();
+ NormalizeClipPlanes();
+
+ MT_Scalar distance;
+ int intersect = INSIDE;
+ // distance: <-------- OUTSIDE -----|----- INTERSECT -----0----- INTERSECT -----|----- INSIDE -------->
+ // -radius radius
+ for (p = 0; p < 6; p++)
+ {
+ distance = m_planes[p][0]*center[0] + m_planes[p][1]*center[1] + m_planes[p][2]*center[2] + m_planes[p][3];
+ if (fabs(distance) <= radius)
+ intersect = INTERSECT;
+ else if (distance < -radius)
+ return OUTSIDE;
+ }
+
+ return intersect;
+}
+
+bool KX_Camera::GetFrustumCulling() const
+{
+ return m_frustum_culling;
+}
+
+void KX_Camera::EnableViewport(bool viewport)
+{
+ m_camdata.m_viewport = viewport;
+}
+
+void KX_Camera::SetViewport(int left, int bottom, int right, int top)
+{
+ m_camdata.m_viewportleft = left;
+ m_camdata.m_viewportbottom = bottom;
+ m_camdata.m_viewportright = right;
+ m_camdata.m_viewporttop = top;
+}
+
+bool KX_Camera::GetViewport() const
+{
+ return m_camdata.m_viewport;
+}
+
+int KX_Camera::GetViewportLeft() const
+{
+ return m_camdata.m_viewportleft;
+}
+
+int KX_Camera::GetViewportBottom() const
+{
+ return m_camdata.m_viewportbottom;
+}
+
+int KX_Camera::GetViewportRight() const
+{
+ return m_camdata.m_viewportright;
+}
+
+int KX_Camera::GetViewportTop() const
+{
+ return m_camdata.m_viewporttop;
+}
+
+//----------------------------------------------------------------------------
+//Python
+
+
+PyMethodDef KX_Camera::Methods[] = {
+ KX_PYMETHODTABLE(KX_Camera, sphereInsideFrustum),
+ KX_PYMETHODTABLE(KX_Camera, boxInsideFrustum),
+ KX_PYMETHODTABLE(KX_Camera, pointInsideFrustum),
+ KX_PYMETHODTABLE(KX_Camera, getCameraToWorld),
+ KX_PYMETHODTABLE(KX_Camera, getWorldToCamera),
+ KX_PYMETHODTABLE(KX_Camera, getProjectionMatrix),
+ KX_PYMETHODTABLE(KX_Camera, setProjectionMatrix),
+ KX_PYMETHODTABLE(KX_Camera, enableViewport),
+ KX_PYMETHODTABLE(KX_Camera, setViewport),
+
+ {NULL,NULL} //Sentinel
+};
+
+char KX_Camera::doc[] = "Module KX_Camera\n\n"
+"Constants:\n"
+"\tINSIDE\n"
+"\tINTERSECT\n"
+"\tOUTSIDE\n"
+"Attributes:\n"
+"\tlens -> float\n"
+"\t\tThe camera's lens value\n"
+"\tnear -> float\n"
+"\t\tThe camera's near clip distance\n"
+"\tfar -> float\n"
+"\t\tThe camera's far clip distance\n"
+"\tfrustum_culling -> bool\n"
+"\t\tNon zero if this camera is frustum culling.\n"
+"\tprojection_matrix -> [[float]]\n"
+"\t\tThis camera's projection matrix.\n"
+"\tmodelview_matrix -> [[float]] (read only)\n"
+"\t\tThis camera's model view matrix.\n"
+"\t\tRegenerated every frame from the camera's position and orientation.\n"
+"\tcamera_to_world -> [[float]] (read only)\n"
+"\t\tThis camera's camera to world transform.\n"
+"\t\tRegenerated every frame from the camera's position and orientation.\n"
+"\tworld_to_camera -> [[float]] (read only)\n"
+"\t\tThis camera's world to camera transform.\n"
+"\t\tRegenerated every frame from the camera's position and orientation.\n"
+"\t\tThis is camera_to_world inverted.\n";
+
+PyTypeObject KX_Camera::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_Camera",
+ sizeof(KX_Camera),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0, 0,
+ doc
+};
+
+PyParentObject KX_Camera::Parents[] = {
+ &KX_Camera::Type,
+ &KX_GameObject::Type,
+ &SCA_IObject::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyObject* KX_Camera::_getattr(const STR_String& attr)
+{
+ if (attr == "INSIDE")
+ return PyInt_FromLong(INSIDE); /* new ref */
+ if (attr == "OUTSIDE")
+ return PyInt_FromLong(OUTSIDE); /* new ref */
+ if (attr == "INTERSECT")
+ return PyInt_FromLong(INTERSECT); /* new ref */
+
+ if (attr == "lens")
+ return PyFloat_FromDouble(GetLens()); /* new ref */
+ if (attr == "near")
+ return PyFloat_FromDouble(GetCameraNear()); /* new ref */
+ if (attr == "far")
+ return PyFloat_FromDouble(GetCameraFar()); /* new ref */
+ if (attr == "frustum_culling")
+ return PyInt_FromLong(m_frustum_culling); /* new ref */
+ if (attr == "perspective")
+ return PyInt_FromLong(m_camdata.m_perspective); /* new ref */
+ if (attr == "projection_matrix")
+ return PyObjectFrom(GetProjectionMatrix()); /* new ref */
+ if (attr == "modelview_matrix")
+ return PyObjectFrom(GetModelviewMatrix()); /* new ref */
+ if (attr == "camera_to_world")
+ return PyObjectFrom(GetCameraToWorld()); /* new ref */
+ if (attr == "world_to_camera")
+ return PyObjectFrom(GetWorldToCamera()); /* new ref */
+
+ _getattr_up(KX_GameObject);
+}
+
+int KX_Camera::_setattr(const STR_String &attr, PyObject *pyvalue)
+{
+ if (PyInt_Check(pyvalue))
+ {
+ if (attr == "frustum_culling")
+ {
+ m_frustum_culling = PyInt_AsLong(pyvalue);
+ return 0;
+ }
+
+ if (attr == "perspective")
+ {
+ m_camdata.m_perspective = PyInt_AsLong(pyvalue);
+ return 0;
+ }
+ }
+
+ if (PyFloat_Check(pyvalue))
+ {
+ if (attr == "lens")
+ {
+ m_camdata.m_lens = PyFloat_AsDouble(pyvalue);
+ m_set_projection_matrix = false;
+ return 0;
+ }
+ if (attr == "near")
+ {
+ m_camdata.m_clipstart = PyFloat_AsDouble(pyvalue);
+ m_set_projection_matrix = false;
+ return 0;
+ }
+ if (attr == "far")
+ {
+ m_camdata.m_clipend = PyFloat_AsDouble(pyvalue);
+ m_set_projection_matrix = false;
+ return 0;
+ }
+ }
+
+ if (PyObject_IsMT_Matrix(pyvalue, 4))
+ {
+ if (attr == "projection_matrix")
+ {
+ MT_Matrix4x4 mat;
+ if (PyMatTo(pyvalue, mat))
+ {
+ SetProjectionMatrix(mat);
+ return 0;
+ }
+ return 1;
+ }
+ }
+ return KX_GameObject::_setattr(attr, pyvalue);
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, sphereInsideFrustum,
+"sphereInsideFrustum(center, radius) -> Integer\n"
+"\treturns INSIDE, OUTSIDE or INTERSECT if the given sphere is\n"
+"\tinside/outside/intersects this camera's viewing frustum.\n\n"
+"\tcenter = the center of the sphere (in world coordinates.)\n"
+"\tradius = the radius of the sphere\n\n"
+"\tExample:\n"
+"\timport GameLogic\n\n"
+"\tco = GameLogic.getCurrentController()\n"
+"\tcam = co.GetOwner()\n\n"
+"\t# A sphere of radius 4.0 located at [x, y, z] = [1.0, 1.0, 1.0]\n"
+"\tif (cam.sphereInsideFrustum([1.0, 1.0, 1.0], 4) != cam.OUTSIDE):\n"
+"\t\t# Sphere is inside frustum !\n"
+"\t\t# Do something useful !\n"
+"\telse:\n"
+"\t\t# Sphere is outside frustum\n"
+)
+{
+ PyObject *pycenter;
+ float radius;
+ if (PyArg_ParseTuple(args, "Of", &pycenter, &radius))
+ {
+ MT_Point3 center;
+ if (PyVecTo(pycenter, center))
+ {
+ return PyInt_FromLong(SphereInsideFrustum(center, radius)); /* new ref */
+ }
+ }
+
+ PyErr_SetString(PyExc_TypeError, "sphereInsideFrustum: Expected arguments: (center, radius)");
+
+ Py_Return;
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, boxInsideFrustum,
+"boxInsideFrustum(box) -> Integer\n"
+"\treturns INSIDE, OUTSIDE or INTERSECT if the given box is\n"
+"\tinside/outside/intersects this camera's viewing frustum.\n\n"
+"\tbox = a list of the eight (8) corners of the box (in world coordinates.)\n\n"
+"\tExample:\n"
+"\timport GameLogic\n\n"
+"\tco = GameLogic.getCurrentController()\n"
+"\tcam = co.GetOwner()\n\n"
+"\tbox = []\n"
+"\tbox.append([-1.0, -1.0, -1.0])\n"
+"\tbox.append([-1.0, -1.0, 1.0])\n"
+"\tbox.append([-1.0, 1.0, -1.0])\n"
+"\tbox.append([-1.0, 1.0, 1.0])\n"
+"\tbox.append([ 1.0, -1.0, -1.0])\n"
+"\tbox.append([ 1.0, -1.0, 1.0])\n"
+"\tbox.append([ 1.0, 1.0, -1.0])\n"
+"\tbox.append([ 1.0, 1.0, 1.0])\n\n"
+"\tif (cam.boxInsideFrustum(box) != cam.OUTSIDE):\n"
+"\t\t# Box is inside/intersects frustum !\n"
+"\t\t# Do something useful !\n"
+"\telse:\n"
+"\t\t# Box is outside the frustum !\n"
+)
+{
+ PyObject *pybox;
+ if (PyArg_ParseTuple(args, "O", &pybox))
+ {
+ unsigned int num_points = PySequence_Size(pybox);
+ if (num_points != 8)
+ {
+ PyErr_Format(PyExc_TypeError, "boxInsideFrustum: Expected eight (8) points, got %d", num_points);
+ return NULL;
+ }
+
+ MT_Point3 box[8];
+ for (unsigned int p = 0; p < 8 ; p++)
+ {
+ PyObject *item = PySequence_GetItem(pybox, p); /* new ref */
+ bool error = !PyVecTo(item, box[p]);
+ Py_DECREF(item);
+ if (error)
+ return NULL;
+ }
+
+ return PyInt_FromLong(BoxInsideFrustum(box)); /* new ref */
+ }
+
+ PyErr_SetString(PyExc_TypeError, "boxInsideFrustum: Expected argument: list of points.");
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, pointInsideFrustum,
+"pointInsideFrustum(point) -> Bool\n"
+"\treturns 1 if the given point is inside this camera's viewing frustum.\n\n"
+"\tpoint = The point to test (in world coordinates.)\n\n"
+"\tExample:\n"
+"\timport GameLogic\n\n"
+"\tco = GameLogic.getCurrentController()\n"
+"\tcam = co.GetOwner()\n\n"
+"\t# Test point [0.0, 0.0, 0.0]"
+"\tif (cam.pointInsideFrustum([0.0, 0.0, 0.0])):\n"
+"\t\t# Point is inside frustum !\n"
+"\t\t# Do something useful !\n"
+"\telse:\n"
+"\t\t# Box is outside the frustum !\n"
+)
+{
+ MT_Point3 point;
+ if (PyVecArgTo(args, point))
+ {
+ return PyInt_FromLong(PointInsideFrustum(point)); /* new ref */
+ }
+
+ PyErr_SetString(PyExc_TypeError, "pointInsideFrustum: Expected point argument.");
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, getCameraToWorld,
+"getCameraToWorld() -> Matrix4x4\n"
+"\treturns the camera to world transformation matrix, as a list of four lists of four values.\n\n"
+"\tie: [[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]])\n"
+)
+{
+ return PyObjectFrom(GetCameraToWorld()); /* new ref */
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, getWorldToCamera,
+"getWorldToCamera() -> Matrix4x4\n"
+"\treturns the world to camera transformation matrix, as a list of four lists of four values.\n\n"
+"\tie: [[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]])\n"
+)
+{
+ return PyObjectFrom(GetWorldToCamera()); /* new ref */
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, getProjectionMatrix,
+"getProjectionMatrix() -> Matrix4x4\n"
+"\treturns this camera's projection matrix, as a list of four lists of four values.\n\n"
+"\tie: [[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]])\n"
+)
+{
+ return PyObjectFrom(GetProjectionMatrix()); /* new ref */
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, setProjectionMatrix,
+"setProjectionMatrix(MT_Matrix4x4 m) -> None\n"
+"\tSets this camera's projection matrix\n"
+"\n"
+"\tExample:\n"
+"\timport GameLogic\n"
+"\t# Set a perspective projection matrix\n"
+"\tdef Perspective(left, right, bottom, top, near, far):\n"
+"\t\tm = MT_Matrix4x4()\n"
+"\t\tm[0][0] = m[0][2] = right - left\n"
+"\t\tm[1][1] = m[1][2] = top - bottom\n"
+"\t\tm[2][2] = m[2][3] = -far - near\n"
+"\t\tm[3][2] = -1\n"
+"\t\tm[3][3] = 0\n"
+"\t\treturn m\n"
+"\n"
+"\t# Set an orthographic projection matrix\n"
+"\tdef Orthographic(left, right, bottom, top, near, far):\n"
+"\t\tm = MT_Matrix4x4()\n"
+"\t\tm[0][0] = right - left\n"
+"\t\tm[0][3] = -right - left\n"
+"\t\tm[1][1] = top - bottom\n"
+"\t\tm[1][3] = -top - bottom\n"
+"\t\tm[2][2] = far - near\n"
+"\t\tm[2][3] = -far - near\n"
+"\t\tm[3][3] = 1\n"
+"\t\treturn m\n"
+"\n"
+"\t# Set an isometric projection matrix\n"
+"\tdef Isometric(left, right, bottom, top, near, far):\n"
+"\t\tm = MT_Matrix4x4()\n"
+"\t\tm[0][0] = m[0][2] = m[1][1] = 0.8660254037844386\n"
+"\t\tm[1][0] = 0.25\n"
+"\t\tm[1][2] = -0.25\n"
+"\t\tm[3][3] = 1\n"
+"\t\treturn m\n"
+"\n"
+"\t"
+"\tco = GameLogic.getCurrentController()\n"
+"\tcam = co.getOwner()\n"
+"\tcam.setProjectionMatrix(Perspective(-1.0, 1.0, -1.0, 1.0, 0.1, 1))\n")
+{
+ PyObject *pymat;
+ if (PyArg_ParseTuple(args, "O", &pymat))
+ {
+ MT_Matrix4x4 mat;
+ if (PyMatTo(pymat, mat))
+ {
+ SetProjectionMatrix(mat);
+ Py_Return;
+ }
+ }
+
+ PyErr_SetString(PyExc_TypeError, "setProjectionMatrix: Expected 4x4 list as matrix argument.");
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, enableViewport,
+"enableViewport(viewport)\n"
+"Sets this camera's viewport status\n"
+)
+{
+ int viewport;
+ if (PyArg_ParseTuple(args,"i",&viewport))
+ {
+ if(viewport)
+ EnableViewport(true);
+ else
+ EnableViewport(false);
+ }
+ Py_Return;
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, setViewport,
+"setViewport(left, bottom, right, top)\n"
+"Sets this camera's viewport\n")
+{
+ int left, bottom, right, top;
+ if (PyArg_ParseTuple(args,"iiii",&left, &bottom, &right, &top))
+ {
+ SetViewport(left, bottom, right, top);
+ }
+ Py_Return;
+}
diff --git a/source/gameengine/Ketsji/KX_Camera.h b/source/gameengine/Ketsji/KX_Camera.h
new file mode 100644
index 00000000000..60f0b107940
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_Camera.h
@@ -0,0 +1,261 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Camera in the gameengine. Cameras are also used for views.
+ */
+
+#ifndef __KX_CAMERA
+#define __KX_CAMERA
+
+
+#include "MT_Transform.h"
+#include "MT_Matrix3x3.h"
+#include "MT_Matrix4x4.h"
+#include "MT_Vector3.h"
+#include "MT_Point3.h"
+#include "KX_GameObject.h"
+#include "IntValue.h"
+#include "RAS_CameraData.h"
+
+class KX_Camera : public KX_GameObject
+{
+ Py_Header;
+protected:
+ /** Camera parameters (clips distances, focal lenght). These
+ * params are closely tied to Blender. In the gameengine, only the
+ * projection and modelview matrices are relevant. There's a
+ * conversion being done in the engine class. Why is it stored
+ * here? It doesn't really have a function here. */
+ RAS_CameraData m_camdata;
+
+ // Never used, I think...
+// void MoveTo(const MT_Point3& movevec)
+// {
+ /*MT_Transform camtrans;
+ camtrans.invert(m_trans1);
+ MT_Matrix3x3 camorient = camtrans.getBasis();
+ camtrans.translate(camorient.inverse()*movevec);
+ m_trans1.invert(camtrans);
+ */
+// }
+
+ /**
+ * Storage for the projection matrix that is passed to the
+ * rasterizer. */
+ MT_Matrix4x4 m_projection_matrix;
+
+ /**
+ * Storage for the modelview matrix that is passed to the
+ * rasterizer. */
+ MT_Matrix4x4 m_modelview_matrix;
+
+ /**
+ * true if the view frustum (modelview/projection matrix)
+ * has changed - the clip planes (m_planes) will have to be
+ * regenerated.
+ */
+ bool m_dirty;
+ /**
+ * true if the frustum planes have been normalized.
+ */
+ bool m_normalized;
+
+ /**
+ * View Frustum clip planes.
+ */
+ MT_Vector4 m_planes[6];
+
+ /**
+ * This camera is frustum culling.
+ * Some cameras (ie if the game was started from a non camera view should not cull.)
+ */
+ bool m_frustum_culling;
+
+ /**
+ * true if this camera has a valid projection matrix.
+ */
+ bool m_set_projection_matrix;
+
+ /**
+ * The center point of the frustum.
+ */
+ MT_Point3 m_frustum_center;
+ MT_Scalar m_frustum_radius;
+ bool m_set_frustum_center;
+
+ /**
+ * Python module doc string.
+ */
+ static char doc[];
+
+ /**
+ * Extracts the camera clip frames from the projection and world-to-camera matrices.
+ */
+ void ExtractClipPlanes();
+ /**
+ * Normalize the camera clip frames.
+ */
+ void NormalizeClipPlanes();
+ /**
+ * Extracts the bound sphere of the view frustum.
+ */
+ void ExtractFrustumSphere();
+public:
+
+ typedef enum { INSIDE, INTERSECT, OUTSIDE } ;
+
+ KX_Camera(void* sgReplicationInfo,SG_Callbacks callbacks,const RAS_CameraData& camdata, bool frustum_culling = true, PyTypeObject *T = &Type);
+ virtual ~KX_Camera();
+
+ MT_Transform GetWorldToCamera() const;
+ MT_Transform GetCameraToWorld() const;
+
+ /**
+ * Not implemented.
+ */
+ void CorrectLookUp(MT_Scalar speed);
+ const MT_Point3 GetCameraLocation() const;
+
+ /* I want the camera orientation as well. */
+ const MT_Quaternion GetCameraOrientation() const;
+
+ /** Sets the projection matrix that is used by the rasterizer. */
+ void SetProjectionMatrix(const MT_Matrix4x4 & mat);
+
+ /** Sets the modelview matrix that is used by the rasterizer. */
+ void SetModelviewMatrix(const MT_Matrix4x4 & mat);
+
+ /** Gets the projection matrix that is used by the rasterizer. */
+ const MT_Matrix4x4& GetProjectionMatrix() const;
+
+ /** returns true if this camera has been set a projection matrix. */
+ bool hasValidProjectionMatrix() const;
+
+ /** Sets the validity of the projection matrix. Call this if you change camera
+ data (eg lens, near plane, far plane) and require the projection matrix to be
+ recalculated.
+ */
+ void InvalidateProjectionMatrix(bool valid = false);
+
+ /** Gets the modelview matrix that is used by the rasterizer.
+ * @warning If the Camera is a dynamic object then this method may return garbage. Use GetCameraToWorld() instead.
+ */
+ const MT_Matrix4x4& GetModelviewMatrix() const;
+
+ /** Gets the focal length. */
+ float GetLens() const;
+ /** Gets the near clip distance. */
+ float GetCameraNear() const;
+ /** Gets the far clip distance. */
+ float GetCameraFar() const;
+ /** Gets all camera data. */
+ RAS_CameraData* GetCameraData();
+
+ /**
+ * Tests if the given sphere is inside this camera's view frustum.
+ *
+ * @param center The center of the sphere, in world coordinates.
+ * @param radius The radius of the sphere.
+ * @return INSIDE, INTERSECT, or OUTSIDE depending on the sphere's relation to the frustum.
+ */
+ int SphereInsideFrustum(const MT_Point3& center, const MT_Scalar &radius);
+ /**
+ * Tests the given eight corners of a box with the view frustum.
+ *
+ * @param box a pointer to eight MT_Point3 representing the world coordinates of the corners of the box.
+ * @return INSIDE, INTERSECT, or OUTSIDE depending on the box's relation to the frustum.
+ */
+ int BoxInsideFrustum(const MT_Point3 *box);
+ /**
+ * Tests the given point against the view frustum.
+ * @return true if the given point is inside or on the view frustum; false if it is outside.
+ */
+ bool PointInsideFrustum(const MT_Point3& x);
+
+ /**
+ * Gets this camera's culling status.
+ */
+ bool GetFrustumCulling() const;
+
+ /**
+ * Sets this camera's viewport status.
+ */
+ void EnableViewport(bool viewport);
+
+ /**
+ * Sets this camera's viewport.
+ */
+ void SetViewport(int left, int bottom, int right, int top);
+
+ /**
+ * Gets this camera's viewport status.
+ */
+ bool GetViewport() const;
+
+ /**
+ * Gets this camera's viewport left.
+ */
+ int GetViewportLeft() const;
+
+ /**
+ * Gets this camera's viewport bottom.
+ */
+ int GetViewportBottom() const;
+
+ /**
+ * Gets this camera's viewport right.
+ */
+ int GetViewportRight() const;
+
+ /**
+ * Gets this camera's viewport top.
+ */
+ int GetViewportTop() const;
+
+
+ KX_PYMETHOD_DOC(KX_Camera, sphereInsideFrustum);
+ KX_PYMETHOD_DOC(KX_Camera, boxInsideFrustum);
+ KX_PYMETHOD_DOC(KX_Camera, pointInsideFrustum);
+
+ KX_PYMETHOD_DOC(KX_Camera, getCameraToWorld);
+ KX_PYMETHOD_DOC(KX_Camera, getWorldToCamera);
+ KX_PYMETHOD_DOC(KX_Camera, getProjectionMatrix);
+ KX_PYMETHOD_DOC(KX_Camera, setProjectionMatrix);
+
+ KX_PYMETHOD_DOC(KX_Camera, enableViewport);
+ KX_PYMETHOD_DOC(KX_Camera, setViewport);
+
+ virtual PyObject* _getattr(const STR_String& attr); /* lens, near, far, projection_matrix */
+ virtual int _setattr(const STR_String& attr, PyObject *pyvalue);
+
+};
+
+#endif //__KX_CAMERA
+
diff --git a/source/gameengine/Ketsji/KX_CameraActuator.cpp b/source/gameengine/Ketsji/KX_CameraActuator.cpp
new file mode 100644
index 00000000000..9454e21132a
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_CameraActuator.cpp
@@ -0,0 +1,526 @@
+/**
+ * KX_CameraActuator.cpp
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_CameraActuator.h"
+#include <iostream>
+#include <math.h>
+#include "KX_GameObject.h"
+
+STR_String KX_CameraActuator::X_AXIS_STRING = "x";
+STR_String KX_CameraActuator::Y_AXIS_STRING = "y";
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+KX_CameraActuator::KX_CameraActuator(
+ SCA_IObject* gameobj,
+ CValue *obj,
+ MT_Scalar hght,
+ MT_Scalar minhght,
+ MT_Scalar maxhght,
+ bool xytog,
+ PyTypeObject* T
+):
+ SCA_IActuator(gameobj, T),
+ m_ob (obj),
+ m_height (hght),
+ m_minHeight (minhght),
+ m_maxHeight (maxhght),
+ m_x (xytog)
+{
+}
+
+KX_CameraActuator::~KX_CameraActuator()
+{
+ //nothing to do
+}
+
+ CValue*
+KX_CameraActuator::
+GetReplica(
+) {
+ KX_CameraActuator* replica = new KX_CameraActuator(*this);
+ replica->ProcessReplica();
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+};
+
+
+
+
+/* three functions copied from blender arith... don't know if there's an equivalent */
+
+static float Kx_Normalize(float *n)
+{
+ 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);
+
+ n[0]/=d;
+ n[1]/=d;
+ n[2]/=d;
+ } else {
+ n[0]=n[1]=n[2]= 0.0;
+ d= 0.0;
+ }
+ return d;
+}
+
+static void Kx_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];
+}
+
+
+static void Kx_VecUpMat3(float *vec, float mat[][3], short axis)
+{
+
+ // Construct a camera matrix s.t. the specified axis
+
+ // maps to the given vector (*vec). Also defines the rotation
+
+ // about this axis by mapping one of the other axis to the y-axis.
+
+
+ float inp;
+ short cox = 0, coy = 0, coz = 0;
+
+ /* up varieeren heeft geen zin, is eigenlijk helemaal geen up!
+ * zie VecUpMat3old
+ */
+
+ 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];
+ Kx_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.0 - inp*mat[coz][2];
+
+ Kx_Normalize((float *)mat[coy]);
+
+ Kx_Crossf(mat[cox], mat[coy], mat[coz]);
+
+}
+
+bool KX_CameraActuator::Update(double curtime, bool frame)
+{
+ bool result = true;
+
+ KX_GameObject *obj = (KX_GameObject*) GetParent();
+ MT_Point3 from = obj->NodeGetWorldPosition();
+ MT_Matrix3x3 frommat = obj->NodeGetWorldOrientation();
+ /* These casts are _very_ dangerous!!! */
+ MT_Point3 lookat = ((KX_GameObject*)m_ob)->NodeGetWorldPosition();
+ MT_Matrix3x3 actormat = ((KX_GameObject*)m_ob)->NodeGetWorldOrientation();
+
+ float fp1[3], fp2[3], rc[3];
+ float inp, fac; //, factor = 0.0; /* some factor... */
+ float mindistsq, maxdistsq, distsq;
+ float mat[3][3];
+
+ /* wondering... is it really neccesary/desirable to suppress negative */
+ /* events here? */
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (bNegativeEvent) return false;
+
+ /* The rules: */
+ /* CONSTRAINT 1: not implemented */
+ /* CONSTRAINT 2: can camera see actor? */
+ /* CONSTRAINT 3: fixed height relative to floor below actor. */
+ /* CONSTRAINT 4: camera rotates behind actor */
+ /* CONSTRAINT 5: minimum / maximum distance */
+ /* CONSTRAINT 6: again: fixed height relative to floor below actor */
+ /* CONSTRAINT 7: track to floor below actor */
+ /* CONSTRAINT 8: look a little bit left or right, depending on how the
+
+ character is looking (horizontal x)
+ */
+
+ /* ...and then set the camera position. Since we assume the parent of */
+ /* this actuator is always a camera, just set the parent position and */
+ /* rotation. We do not check whether we really have a camera as parent. */
+ /* It may be better to turn this into a general tracking actuator later */
+ /* on, since lots of plausible relations can be filled in here. */
+
+ /* ... set up some parameters ... */
+ /* missing here: the 'floorloc' of the actor's shadow */
+
+ mindistsq= m_minHeight*m_minHeight;
+ maxdistsq= m_maxHeight*m_maxHeight;
+
+ /* C1: not checked... is a future option */
+
+ /* C2: blender test_visibility function. Can this be a ray-test? */
+
+ /* C3: fixed height */
+ from[2] = (15.0*from[2] + lookat[2] + m_height)/16.0;
+
+
+ /* C4: camera behind actor */
+ if (m_x) {
+ fp1[0] = actormat[0][0];
+ fp1[1] = actormat[1][0];
+ fp1[2] = actormat[2][0];
+
+ fp2[0] = frommat[0][0];
+ fp2[1] = frommat[1][0];
+ fp2[2] = frommat[2][0];
+ }
+ else {
+ fp1[0] = actormat[0][1];
+ fp1[1] = actormat[1][1];
+ fp1[2] = actormat[2][1];
+
+ fp2[0] = frommat[0][1];
+ fp2[1] = frommat[1][1];
+ fp2[2] = frommat[2][1];
+ }
+
+ inp= fp1[0]*fp2[0] + fp1[1]*fp2[1] + fp1[2]*fp2[2];
+ fac= (-1.0 + inp)/32.0;
+
+ from[0]+= fac*fp1[0];
+ from[1]+= fac*fp1[1];
+ from[2]+= fac*fp1[2];
+
+ /* alleen alstie ervoor ligt: cross testen en loodrechte bijtellen */
+ if(inp<0.0) {
+ if(fp1[0]*fp2[1] - fp1[1]*fp2[0] > 0.0) {
+ from[0]-= fac*fp1[1];
+ from[1]+= fac*fp1[0];
+ }
+ else {
+ from[0]+= fac*fp1[1];
+ from[1]-= fac*fp1[0];
+ }
+ }
+
+ /* CONSTRAINT 5: minimum / maximum afstand */
+
+ rc[0]= (lookat[0]-from[0]);
+ rc[1]= (lookat[1]-from[1]);
+ rc[2]= (lookat[2]-from[2]);
+ distsq= rc[0]*rc[0] + rc[1]*rc[1] + rc[2]*rc[2];
+
+ if(distsq > maxdistsq) {
+ distsq = 0.15*(distsq-maxdistsq)/distsq;
+
+ from[0] += distsq*rc[0];
+ from[1] += distsq*rc[1];
+ from[2] += distsq*rc[2];
+ }
+ else if(distsq < mindistsq) {
+ distsq = 0.15*(mindistsq-distsq)/mindistsq;
+
+ from[0] -= distsq*rc[0];
+ from[1] -= distsq*rc[1];
+ from[2] -= distsq*rc[2];
+ }
+
+
+ /* CONSTRAINT 7: track to schaduw */
+ rc[0]= (lookat[0]-from[0]);
+ rc[1]= (lookat[1]-from[1]);
+ rc[2]= (lookat[2]-from[2]);
+ Kx_VecUpMat3(rc, mat, 3); /* y up Track -z */
+
+
+
+
+ /* now set the camera position and rotation */
+
+ obj->NodeSetLocalPosition(from);
+
+ actormat[0][0]= mat[0][0]; actormat[0][1]= mat[1][0]; actormat[0][2]= mat[2][0];
+ actormat[1][0]= mat[0][1]; actormat[1][1]= mat[1][1]; actormat[1][2]= mat[2][1];
+ actormat[2][0]= mat[0][2]; actormat[2][1]= mat[1][2]; actormat[2][2]= mat[2][2];
+ obj->NodeSetLocalOrientation(actormat);
+
+ return result;
+}
+
+CValue *KX_CameraActuator::findObject(char *obName)
+{
+ /* hook to object system */
+ return NULL;
+}
+
+bool KX_CameraActuator::string2axischoice(const char *axisString)
+{
+ bool res = true;
+
+ res = !(axisString == Y_AXIS_STRING);
+
+ return res;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_CameraActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_CameraActuator",
+ sizeof(KX_CameraActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_CameraActuator::Parents[] = {
+ &KX_CameraActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_CameraActuator::Methods[] = {
+ {"setObject",(PyCFunction) KX_CameraActuator::sPySetObject, METH_VARARGS, SetObject_doc},
+ {"getObject",(PyCFunction) KX_CameraActuator::sPyGetObject, METH_NOARGS, GetObject_doc},
+ {"setMin" ,(PyCFunction) KX_CameraActuator::sPySetMin, METH_VARARGS, SetMin_doc},
+ {"getMin" ,(PyCFunction) KX_CameraActuator::sPyGetMin, METH_NOARGS, GetMin_doc},
+ {"setMax" ,(PyCFunction) KX_CameraActuator::sPySetMax, METH_VARARGS, SetMax_doc},
+ {"getMax" ,(PyCFunction) KX_CameraActuator::sPyGetMax, METH_NOARGS, GetMax_doc},
+ {"setHeight",(PyCFunction) KX_CameraActuator::sPySetHeight, METH_VARARGS, SetHeight_doc},
+ {"getHeight",(PyCFunction) KX_CameraActuator::sPyGetHeight, METH_NOARGS, GetHeight_doc},
+ {"setXY" ,(PyCFunction) KX_CameraActuator::sPySetXY, METH_VARARGS, SetXY_doc},
+ {"getXY" ,(PyCFunction) KX_CameraActuator::sPyGetXY, METH_VARARGS, GetXY_doc},
+ {NULL,NULL,NULL,NULL} //Sentinel
+};
+
+PyObject* KX_CameraActuator::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IActuator);
+}
+/* get obj ---------------------------------------------------------- */
+char KX_CameraActuator::GetObject_doc[] =
+"getObject\n"
+"\tReturns the object this sensor reacts to.\n";
+PyObject* KX_CameraActuator::PyGetObject(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyString_FromString(m_ob->GetName());
+}
+/* set obj ---------------------------------------------------------- */
+char KX_CameraActuator::SetObject_doc[] =
+"setObject\n"
+"\tSets the object this sensor reacts to.\n";
+PyObject* KX_CameraActuator::PySetObject(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ PyObject* gameobj;
+ if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj))
+ {
+ m_ob = (CValue*)gameobj;
+ Py_Return;
+ }
+ PyErr_Clear();
+
+ char* objectname;
+ if (PyArg_ParseTuple(args, "s", &objectname))
+ {
+ CValue *object = (CValue*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname));
+ if(object)
+ {
+ m_ob = object;
+ Py_Return;
+ }
+ }
+
+ return NULL;
+}
+
+/* get min ---------------------------------------------------------- */
+char KX_CameraActuator::GetMin_doc[] =
+"getMin\n"
+"\tReturns the minimum value set in the Min: field.\n";
+PyObject* KX_CameraActuator::PyGetMin(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyFloat_FromDouble(m_minHeight);
+}
+/* set min ---------------------------------------------------------- */
+char KX_CameraActuator::SetMin_doc[] =
+"setMin\n"
+"\tSets the minimum value.\n";
+PyObject* KX_CameraActuator::PySetMin(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float min;
+ if(PyArg_ParseTuple(args,"f", &min))
+ {
+ m_minHeight = min;
+ Py_Return;
+ }
+ return NULL;
+}
+/* get min ---------------------------------------------------------- */
+char KX_CameraActuator::GetMax_doc[] =
+"getMax\n"
+"\tReturns the maximum value set in the Max: field.\n";
+PyObject* KX_CameraActuator::PyGetMax(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyFloat_FromDouble(m_maxHeight);
+}
+/* set min ---------------------------------------------------------- */
+char KX_CameraActuator::SetMax_doc[] =
+"setMax\n"
+"\tSets the maximum value.\n";
+PyObject* KX_CameraActuator::PySetMax(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float max;
+ if(PyArg_ParseTuple(args,"f", &max))
+ {
+ m_maxHeight = max;
+ Py_Return;
+ }
+ return NULL;
+}
+/* get height ---------------------------------------------------------- */
+char KX_CameraActuator::GetHeight_doc[] =
+"getHeight\n"
+"\tReturns the height value set in the height: field.\n";
+PyObject* KX_CameraActuator::PyGetHeight(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyFloat_FromDouble(m_height);
+}
+/* set height ---------------------------------------------------------- */
+char KX_CameraActuator::SetHeight_doc[] =
+"setHeight\n"
+"\tSets the height value.\n";
+PyObject* KX_CameraActuator::PySetHeight(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float height;
+ if(PyArg_ParseTuple(args,"f", &height))
+ {
+ m_height = height;
+ Py_Return;
+ }
+ return NULL;
+}
+/* set XY ---------------------------------------------------------- */
+char KX_CameraActuator::SetXY_doc[] =
+"setXY\n"
+"\tSets axis the camera tries to get behind.\n"
+"\t1=x, 0=y\n";
+PyObject* KX_CameraActuator::PySetXY(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int value;
+ if(PyArg_ParseTuple(args,"i", &value))
+ {
+ m_x = value != 0;
+ Py_Return;
+ }
+ return NULL;
+}
+
+/* get XY -------------------------------------------------------------*/
+char KX_CameraActuator::GetXY_doc[] =
+"getXY\n"
+"\tGets the axis the camera tries to get behind.\n"
+"\tTrue = X, False = Y\n";
+PyObject* KX_CameraActuator::PyGetXY(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyInt_FromLong(m_x);
+}
+
+/* eof */
diff --git a/source/gameengine/Ketsji/KX_CameraActuator.h b/source/gameengine/Ketsji/KX_CameraActuator.h
new file mode 100644
index 00000000000..27d8a77b28d
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_CameraActuator.h
@@ -0,0 +1,140 @@
+/**
+ * KX_CameraActuator.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 __KX_CAMERAACTUATOR
+#define __KX_CAMERAACTUATOR
+
+#include "SCA_IActuator.h"
+#include "MT_Scalar.h"
+#include "SCA_LogicManager.h"
+
+/**
+ * The camera actuator does a Robbie Muller prespective for you. This is a
+ * weird set of rules that positions the camera sort of behind the object,
+ * tracking, while avoiding any objects between the 'ideal' position and the
+ * actor being tracked.
+ */
+
+
+class KX_CameraActuator : public SCA_IActuator
+{
+ Py_Header;
+private :
+ /** Object that will be tracked. */
+ CValue *m_ob;
+
+ /** height (float), */
+ //const MT_Scalar m_height;
+ /** min (float), */
+ //const MT_Scalar m_minHeight;
+ /** max (float), */
+ //const MT_Scalar m_maxHeight;
+
+ /** height (float), */
+ MT_Scalar m_height;
+
+ /** min (float), */
+ MT_Scalar m_minHeight;
+
+ /** max (float), */
+ MT_Scalar m_maxHeight;
+
+ /** xy toggle (pick one): true == x, false == y */
+ bool m_x;
+
+ /* get the KX_IGameObject with this name */
+ CValue *findObject(char *obName);
+
+ /* parse x or y to a toggle pick */
+ bool string2axischoice(const char *axisString);
+
+ public:
+ static STR_String X_AXIS_STRING;
+ static STR_String Y_AXIS_STRING;
+
+ /**
+ * Set the bool toggle to true to use x lock, false for y lock
+ */
+ KX_CameraActuator(
+
+ SCA_IObject *gameobj,
+ //const CValue *ob,
+ CValue *ob,
+ MT_Scalar hght,
+ MT_Scalar minhght,
+ MT_Scalar maxhght,
+ bool xytog,
+ PyTypeObject* T=&Type
+
+ );
+
+
+ ~KX_CameraActuator();
+
+
+
+ /** Methods Inherited from CValue */
+ CValue* GetReplica();
+
+
+ /** Methods inherited from SCA_IActuator */
+ virtual bool Update(
+ double curtime,
+ bool frame
+ );
+
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ /* set object to look at */
+ KX_PYMETHOD_DOC(KX_CameraActuator,SetObject);
+ /* get current object */
+ KX_PYMETHOD_DOC(KX_CameraActuator,GetObject);
+ KX_PYMETHOD_DOC(KX_CameraActuator,SetMin);
+ KX_PYMETHOD_DOC(KX_CameraActuator,GetMin);
+ KX_PYMETHOD_DOC(KX_CameraActuator,SetMax);
+ KX_PYMETHOD_DOC(KX_CameraActuator,GetMax);
+ KX_PYMETHOD_DOC(KX_CameraActuator,SetHeight);
+ KX_PYMETHOD_DOC(KX_CameraActuator,GetHeight);
+ KX_PYMETHOD_DOC(KX_CameraActuator,SetXY);
+ KX_PYMETHOD_DOC(KX_CameraActuator,GetXY);
+
+};
+
+#endif //__KX_CAMERAACTUATOR
+
diff --git a/source/gameengine/Ketsji/KX_CameraIpoSGController.cpp b/source/gameengine/Ketsji/KX_CameraIpoSGController.cpp
new file mode 100644
index 00000000000..38064739ff0
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_CameraIpoSGController.cpp
@@ -0,0 +1,129 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_CameraIpoSGController.h"
+#include "KX_ScalarInterpolator.h"
+#include "KX_Camera.h"
+#include "RAS_CameraData.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(_WIN64)
+typedef unsigned __int64 uint_ptr;
+#else
+typedef unsigned long uint_ptr;
+#endif
+
+bool KX_CameraIpoSGController::Update(double currentTime)
+{
+ if (m_modified)
+ {
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ (*i)->Execute(m_ipotime);
+ }
+
+ SG_Spatial* ob = (SG_Spatial*)m_pObject;
+ KX_Camera* kxcamera = (KX_Camera*) ob->GetSGClientObject();
+ RAS_CameraData* camdata = kxcamera->GetCameraData();
+
+ if (m_modify_lens)
+ camdata->m_lens = m_lens;
+
+ if (m_modify_clipstart )
+ camdata->m_clipstart = m_clipstart;
+
+ if (m_modify_clipend)
+ camdata->m_clipend = m_clipend;
+
+ if (m_modify_lens || m_modify_clipstart || m_modify_clipend)
+ kxcamera->InvalidateProjectionMatrix();
+
+ m_modified=false;
+ }
+ return false;
+}
+
+
+void KX_CameraIpoSGController::AddInterpolator(KX_IInterpolator* interp)
+{
+ this->m_interpolators.push_back(interp);
+}
+
+SG_Controller* KX_CameraIpoSGController::GetReplica(class SG_Node* destnode)
+{
+ KX_CameraIpoSGController* iporeplica = new KX_CameraIpoSGController(*this);
+ // clear object that ipo acts on
+ iporeplica->ClearObject();
+
+ // dirty hack, ask Gino for a better solution in the ipo implementation
+ // hacken en zagen, in what we call datahiding, not written for replication :(
+
+ T_InterpolatorList oldlist = m_interpolators;
+ iporeplica->m_interpolators.clear();
+
+ T_InterpolatorList::iterator i;
+ for (i = oldlist.begin(); !(i == oldlist.end()); ++i) {
+ KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i));
+ iporeplica->AddInterpolator(copyipo);
+
+ MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget();
+ uint_ptr orgbase = (uint_ptr)this;
+ uint_ptr orgloc = (uint_ptr)scaal;
+ uint_ptr offset = orgloc-orgbase;
+ uint_ptr newaddrbase = (uint_ptr)iporeplica + offset;
+ MT_Scalar* blaptr = (MT_Scalar*) newaddrbase;
+ copyipo->SetNewTarget((MT_Scalar*)blaptr);
+ }
+
+ return iporeplica;
+}
+
+KX_CameraIpoSGController::~KX_CameraIpoSGController()
+{
+
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ delete (*i);
+ }
+
+}
+
+ void
+KX_CameraIpoSGController::SetOption(
+ int option,
+ int value)
+{
+ /* Setting options */
+
+}
diff --git a/source/gameengine/Ketsji/KX_CameraIpoSGController.h b/source/gameengine/Ketsji/KX_CameraIpoSGController.h
new file mode 100644
index 00000000000..d80847fa5fb
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_CameraIpoSGController.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef KX_CAMERAIPOSGCONTROLLER_H
+#define KX_CAMERAIPOSGCONTROLLER_H
+
+#include "SG_Controller.h"
+#include "SG_Spatial.h"
+
+#include "KX_IInterpolator.h"
+
+struct RAS_CameraData;
+
+class KX_CameraIpoSGController : public SG_Controller
+{
+public:
+ MT_Scalar m_lens;
+ MT_Scalar m_clipstart;
+ MT_Scalar m_clipend;
+
+private:
+ T_InterpolatorList m_interpolators;
+ unsigned short m_modify_lens : 1;
+ unsigned short m_modify_clipstart : 1;
+ unsigned short m_modify_clipend : 1;
+ bool m_modified;
+
+ double m_ipotime;
+public:
+ KX_CameraIpoSGController() :
+ m_modify_lens(false),
+ m_modify_clipstart(false),
+ m_modify_clipend(false),
+ m_modified(true),
+ m_ipotime(0.0)
+ {}
+
+ ~KX_CameraIpoSGController();
+ SG_Controller* GetReplica(class SG_Node* destnode);
+ bool Update(double time);
+
+ void
+ SetOption(
+ int option,
+ int value
+ );
+
+ void SetSimulatedTime(double time) {
+ m_ipotime = time;
+ m_modified = true;
+ }
+ void SetModifyLens(bool modify) {
+ m_modify_lens = modify;
+ }
+ void SetModifyClipEnd(bool modify) {
+ m_modify_clipend = modify;
+ }
+ void SetModifyClipStart(bool modify) {
+ m_modify_clipstart = modify;
+ }
+ void AddInterpolator(KX_IInterpolator* interp);
+};
+
+#endif // KX_CAMERAIPOSGCONTROLLER_H
+
diff --git a/source/gameengine/Ketsji/KX_ClientObjectInfo.h b/source/gameengine/Ketsji/KX_ClientObjectInfo.h
new file mode 100644
index 00000000000..237ec137a1c
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ClientObjectInfo.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 __KX_CLIENTOBJECT_INFO_H
+#define __KX_CLIENTOBJECT_INFO_H
+
+#include <SM_Object.h>
+
+#include <list>
+
+class SCA_ISensor;
+class KX_GameObject;
+/**
+ * Client Type and Additional Info. This structure can be use instead of a bare void* pointer, for safeness, and additional info for callbacks
+ */
+struct KX_ClientObjectInfo : public SM_ClientObject
+{
+ enum clienttype {
+ STATIC,
+ ACTOR,
+ RESERVED1,
+ RADAR,
+ NEAR
+ } m_type;
+ KX_GameObject* m_gameobject;
+ void* m_auxilary_info;
+ std::list<SCA_ISensor*> m_sensors;
+public:
+ KX_ClientObjectInfo(KX_GameObject *gameobject, clienttype type = STATIC, void *auxilary_info = NULL) :
+ SM_ClientObject(),
+ m_type(type),
+ m_gameobject(gameobject),
+ m_auxilary_info(auxilary_info)
+ {}
+
+ KX_ClientObjectInfo(const KX_ClientObjectInfo &copy)
+ : SM_ClientObject(copy),
+ m_type(copy.m_type),
+ m_gameobject(copy.m_gameobject),
+ m_auxilary_info(copy.m_auxilary_info)
+ {
+ }
+
+ virtual ~KX_ClientObjectInfo() {}
+
+ virtual bool hasCollisionCallback()
+ {
+ return m_sensors.size() != 0;
+ }
+
+ bool isActor() { return m_type <= ACTOR; }
+};
+
+#endif //__KX_CLIENTOBJECT_INFO_H
+
diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
new file mode 100644
index 00000000000..c53749131c0
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
@@ -0,0 +1,377 @@
+/**
+ * Apply a constraint to a position or rotation value
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SCA_IActuator.h"
+#include "KX_ConstraintActuator.h"
+#include "SCA_IObject.h"
+#include "MT_Point3.h"
+#include "MT_Matrix3x3.h"
+#include "KX_GameObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj,
+ int dampTime,
+ float minBound,
+ float maxBound,
+ int locrotxyz,
+ PyTypeObject* T)
+ : SCA_IActuator(gameobj, T)
+{
+ m_dampTime = dampTime;
+ m_locrot = locrotxyz;
+ /* The units of bounds are determined by the type of constraint. To */
+ /* make the constraint application easier and more transparent later on, */
+ /* I think converting the bounds to the applicable domain makes more */
+ /* sense. */
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_LOCX:
+ case KX_ACT_CONSTRAINT_LOCY:
+ case KX_ACT_CONSTRAINT_LOCZ:
+ m_minimumBound = minBound;
+ m_maximumBound = maxBound;
+ break;
+ case KX_ACT_CONSTRAINT_ROTX:
+ case KX_ACT_CONSTRAINT_ROTY:
+ case KX_ACT_CONSTRAINT_ROTZ:
+ /* The user interface asks for degrees, we are radian. */
+ m_minimumBound = MT_radians(minBound);
+ m_maximumBound = MT_radians(maxBound);
+ break;
+ default:
+ ; /* error */
+ }
+
+} /* End of constructor */
+
+KX_ConstraintActuator::~KX_ConstraintActuator()
+{
+ // there's nothing to be done here, really....
+} /* end of destructor */
+
+bool KX_ConstraintActuator::Update(double curtime, bool frame)
+{
+
+ bool result = false;
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (bNegativeEvent)
+ return false; // do nothing on negative events
+
+ /* Constraint clamps the values to the specified range, with a sort of */
+ /* low-pass filtered time response, if the damp time is unequal to 0. */
+
+ /* Having to retrieve location/rotation and setting it afterwards may not */
+ /* be efficient enough... Somthing to look at later. */
+ KX_GameObject *parent = (KX_GameObject*) GetParent();
+ MT_Point3 position = parent->NodeGetWorldPosition();
+ MT_Matrix3x3 rotation = parent->NodeGetWorldOrientation();
+// MT_Vector3 eulerrot = rotation.getEuler();
+
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_LOCX:
+ Clamp(position[0], m_minimumBound, m_maximumBound);
+ result = true;
+ break;
+ case KX_ACT_CONSTRAINT_LOCY:
+ Clamp(position[1], m_minimumBound, m_maximumBound);
+ result = true;
+ break;
+ case KX_ACT_CONSTRAINT_LOCZ:
+ Clamp(position[2], m_minimumBound, m_maximumBound);
+ result = true;
+ break;
+
+// case KX_ACT_CONSTRAINT_ROTX:
+// /* The angles are Euler angles (I think that's what they are called) */
+// /* but we need to convert from/to the MT_Matrix3x3. */
+// Clamp(eulerrot[0], m_minimumBound, m_maximumBound);
+// break;
+// case KX_ACT_CONSTRAINT_ROTY:
+// Clamp(eulerrot[1], m_minimumBound, m_maximumBound);
+// break;
+// case KX_ACT_CONSTRAINT_ROTZ:
+// Clamp(eulerrot[2], m_minimumBound, m_maximumBound);
+// break;
+// default:
+// ; /* error */
+ }
+
+ /* Will be replaced by a filtered clamp. */
+
+
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_LOCX:
+ case KX_ACT_CONSTRAINT_LOCY:
+ case KX_ACT_CONSTRAINT_LOCZ:
+ parent->NodeSetLocalPosition(position);
+ break;
+
+
+// case KX_ACT_CONSTRAINT_ROTX:
+// case KX_ACT_CONSTRAINT_ROTY:
+// case KX_ACT_CONSTRAINT_ROTZ:
+// rotation.setEuler(eulerrot);
+// parent->NodeSetLocalOrientation(rotation);
+ break;
+
+ default:
+ ; /* error */
+ }
+
+ return result;
+} /* end of KX_ConstraintActuator::Update(double curtime,double deltatime) */
+
+void KX_ConstraintActuator::Clamp(MT_Scalar &var,
+ float min,
+ float max) {
+ if (var < min) {
+ var = min;
+ } else if (var > max) {
+ var = max;
+ }
+}
+
+
+bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE m)
+{
+ bool res = false;
+
+ if ( (m > KX_ACT_CONSTRAINT_NODEF) && (m < KX_ACT_CONSTRAINT_MAX)) {
+ res = true;
+ }
+
+ return res;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_ConstraintActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_ConstraintActuator",
+ sizeof(KX_ConstraintActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_ConstraintActuator::Parents[] = {
+ &KX_ConstraintActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_ConstraintActuator::Methods[] = {
+ {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, SetDamp_doc},
+ {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_VARARGS, GetDamp_doc},
+ {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetMin_doc},
+ {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetMin_doc},
+ {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetMax_doc},
+ {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetMax_doc},
+ {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, SetLimit_doc},
+ {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_VARARGS, GetLimit_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* KX_ConstraintActuator::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IActuator);
+}
+
+/* 2. setDamp */
+char KX_ConstraintActuator::SetDamp_doc[] =
+"setDamp(duration)\n"
+"\t- duration: integer\n"
+"\tSets the time with which the constraint application is delayed.\n"
+"\tIf the duration is negative, it is set to 0.\n";
+PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int dampArg;
+ if(!PyArg_ParseTuple(args, "i", &dampArg)) {
+ return NULL;
+ }
+
+ m_dampTime = dampArg;
+ if (m_dampTime < 0) m_dampTime = 0;
+
+ Py_Return;
+}
+/* 3. getDamp */
+char KX_ConstraintActuator::GetDamp_doc[] =
+"GetDamp()\n"
+"\tReturns the damping time for application of the constraint.\n";
+PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self,
+ PyObject* args,
+ PyObject* kwds){
+ return PyInt_FromLong(m_dampTime);
+}
+
+/* 4. setMin */
+char KX_ConstraintActuator::SetMin_doc[] =
+"setMin(lower_bound)\n"
+"\t- lower_bound: float\n"
+"\tSets the lower value of the interval to which the value\n"
+"\tis clipped.\n";
+PyObject* KX_ConstraintActuator::PySetMin(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float minArg;
+ if(!PyArg_ParseTuple(args, "f", &minArg)) {
+ return NULL;
+ }
+
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_LOCX:
+ case KX_ACT_CONSTRAINT_LOCY:
+ case KX_ACT_CONSTRAINT_LOCZ:
+ m_minimumBound = minArg;
+ break;
+ case KX_ACT_CONSTRAINT_ROTX:
+ case KX_ACT_CONSTRAINT_ROTY:
+ case KX_ACT_CONSTRAINT_ROTZ:
+ m_minimumBound = MT_radians(minArg);
+ break;
+ default:
+ ; /* error */
+ }
+
+ Py_Return;
+}
+/* 5. getMin */
+char KX_ConstraintActuator::GetMin_doc[] =
+"getMin()\n"
+"\tReturns the lower value of the interval to which the value\n"
+"\tis clipped.\n";
+PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return PyFloat_FromDouble(m_minimumBound);
+}
+
+/* 6. setMax */
+char KX_ConstraintActuator::SetMax_doc[] =
+"setMax(upper_bound)\n"
+"\t- upper_bound: float\n"
+"\tSets the upper value of the interval to which the value\n"
+"\tis clipped.\n";
+PyObject* KX_ConstraintActuator::PySetMax(PyObject* self,
+ PyObject* args,
+ PyObject* kwds){
+ float maxArg;
+ if(!PyArg_ParseTuple(args, "f", &maxArg)) {
+ return NULL;
+ }
+
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_LOCX:
+ case KX_ACT_CONSTRAINT_LOCY:
+ case KX_ACT_CONSTRAINT_LOCZ:
+ m_maximumBound = maxArg;
+ break;
+ case KX_ACT_CONSTRAINT_ROTX:
+ case KX_ACT_CONSTRAINT_ROTY:
+ case KX_ACT_CONSTRAINT_ROTZ:
+ m_maximumBound = MT_radians(maxArg);
+ break;
+ default:
+ ; /* error */
+ }
+
+ Py_Return;
+}
+/* 7. getMax */
+char KX_ConstraintActuator::GetMax_doc[] =
+"getMax()\n"
+"\tReturns the upper value of the interval to which the value\n"
+"\tis clipped.\n";
+PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return PyFloat_FromDouble(m_maximumBound);
+}
+
+
+/* This setter/getter probably for the constraint type */
+/* 8. setLimit */
+char KX_ConstraintActuator::SetLimit_doc[] =
+"setLimit(type)\n"
+"\t- type: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY,\n"
+"\t KX_CONSTRAINTACT_LOCZ, KX_CONSTRAINTACT_ROTX,\n"
+"\t KX_CONSTRAINTACT_ROTY, or KX_CONSTRAINTACT_ROTZ.\n"
+"\tSets the type of constraint.\n";
+PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int locrotArg;
+ if(!PyArg_ParseTuple(args, "i", &locrotArg)) {
+ return NULL;
+ }
+
+ if (IsValidMode((KX_CONSTRAINTTYPE)locrotArg)) m_locrot = locrotArg;
+
+ Py_Return;
+}
+/* 9. getLimit */
+char KX_ConstraintActuator::GetLimit_doc[] =
+"getLimit(type)\n"
+"\tReturns the type of constraint.\n";
+PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return PyInt_FromLong(m_locrot);
+}
+
+/* eof */
diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h
new file mode 100644
index 00000000000..dfd39f1455c
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h
@@ -0,0 +1,110 @@
+/**
+ * KX_ConstraintActuator.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 __KX_CONSTRAINTACTUATOR
+#define __KX_CONSTRAINTACTUATOR
+
+#include "SCA_IActuator.h"
+#include "MT_Scalar.h"
+
+class KX_ConstraintActuator : public SCA_IActuator
+{
+ Py_Header;
+protected:
+ // Damp time (int),
+ int m_dampTime;
+ // min (float),
+ float m_minimumBound;
+ // max (float),
+ float m_maximumBound;
+ // locrotxyz choice (pick one): only one choice allowed at a time!
+ int m_locrot;
+
+ /**
+ * Clamp <var> to <min>, <max>. Borders are included (in as far as
+ * float comparisons are good for equality...).
+ */
+ void Clamp(MT_Scalar &var, float min, float max);
+
+
+ public:
+ enum KX_CONSTRAINTTYPE {
+ KX_ACT_CONSTRAINT_NODEF = 0,
+ KX_ACT_CONSTRAINT_LOCX,
+ KX_ACT_CONSTRAINT_LOCY,
+ KX_ACT_CONSTRAINT_LOCZ,
+ KX_ACT_CONSTRAINT_ROTX,
+ KX_ACT_CONSTRAINT_ROTY,
+ KX_ACT_CONSTRAINT_ROTZ,
+ KX_ACT_CONSTRAINT_MAX
+ };
+
+ bool IsValidMode(KX_CONSTRAINTTYPE m);
+
+ KX_ConstraintActuator(SCA_IObject* gameobj,
+ int damptime,
+ float min,
+ float max,
+ int locrot,
+ PyTypeObject* T=&Type);
+ virtual ~KX_ConstraintActuator();
+ virtual CValue* GetReplica() {
+ KX_ConstraintActuator* replica = new KX_ConstraintActuator(*this);
+ replica->ProcessReplica();
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+ };
+
+ virtual bool Update(double curtime, bool frame);
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetDamp);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,GetDamp);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMin);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,GetMin);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMax);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,GetMax);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetLimit);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,GetLimit);
+
+};
+
+#endif //__KX_CONSTRAINTACTUATOR
+
diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp
new file mode 100644
index 00000000000..9ca9517c035
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp
@@ -0,0 +1,137 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 <Python.h>
+#include "KX_ConstraintWrapper.h"
+#include "PHY_IPhysicsEnvironment.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_ConstraintWrapper::KX_ConstraintWrapper(
+ PHY_ConstraintType ctype,
+ int constraintId,
+ PHY_IPhysicsEnvironment* physenv,PyTypeObject *T) :
+ PyObjectPlus(T),
+ m_constraintId(constraintId),
+ m_constraintType(ctype),
+ m_physenv(physenv)
+{
+}
+KX_ConstraintWrapper::~KX_ConstraintWrapper()
+{
+}
+//python integration methods
+PyObject* KX_ConstraintWrapper::PyTestMethod(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* KX_ConstraintWrapper::PyGetConstraintId(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyInt_FromLong(m_constraintId);
+}
+
+
+
+
+//python specific stuff
+PyTypeObject KX_ConstraintWrapper::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_ConstraintWrapper",
+ sizeof(KX_ConstraintWrapper),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_ConstraintWrapper::Parents[] = {
+ &KX_ConstraintWrapper::Type,
+ NULL
+};
+
+PyObject* KX_ConstraintWrapper::_getattr(const STR_String& attr)
+{
+ //here you can search for existing data members (like mass,friction etc.)
+ _getattr_up(PyObjectPlus);
+}
+
+int KX_ConstraintWrapper::_setattr(const STR_String& attr,PyObject* pyobj)
+{
+
+ PyTypeObject* type = pyobj->ob_type;
+ int result = 1;
+
+ if (type == &PyList_Type)
+ {
+ result = 0;
+ }
+ if (type == &PyFloat_Type)
+ {
+ result = 0;
+
+ }
+ if (type == &PyInt_Type)
+ {
+ result = 0;
+ }
+ if (type == &PyString_Type)
+ {
+ result = 0;
+ }
+ if (result)
+ result = PyObjectPlus::_setattr(attr,pyobj);
+ return result;
+};
+
+
+PyMethodDef KX_ConstraintWrapper::Methods[] = {
+ {"testMethod",(PyCFunction) KX_ConstraintWrapper::sPyTestMethod, METH_VARARGS},
+ {"getConstraintId",(PyCFunction) KX_ConstraintWrapper::sPyGetConstraintId, METH_VARARGS},
+ {NULL,NULL} //Sentinel
+};
diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.h b/source/gameengine/Ketsji/KX_ConstraintWrapper.h
new file mode 100644
index 00000000000..12fd7fbe292
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.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 KX_CONSTRAINT_WRAPPER
+#define KX_CONSTRAINT_WRAPPER
+
+#include "Value.h"
+#include "PHY_DynamicTypes.h"
+
+class KX_ConstraintWrapper : public PyObjectPlus
+{
+ Py_Header;
+ virtual PyObject* _getattr(const STR_String& attr);
+ virtual int _setattr(const STR_String& attr, PyObject *value);
+public:
+ KX_ConstraintWrapper(PHY_ConstraintType ctype,int constraintId,class PHY_IPhysicsEnvironment* physenv,PyTypeObject *T = &Type);
+ virtual ~KX_ConstraintWrapper ();
+ int getConstraintId() { return m_constraintId;};
+
+ KX_PYMETHOD(KX_ConstraintWrapper,TestMethod);
+ KX_PYMETHOD(KX_ConstraintWrapper,GetConstraintId);
+
+private:
+ int m_constraintId;
+ PHY_ConstraintType m_constraintType;
+ PHY_IPhysicsEnvironment* m_physenv;
+};
+
+#endif //KX_CONSTRAINT_WRAPPER
+
diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h b/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h
new file mode 100644
index 00000000000..684e052323d
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObject.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 KX_CONVERTPHYSICSOBJECTS
+#define KX_CONVERTPHYSICSOBJECTS
+
+/* These are defined by the build system... */
+//but the build system is broken, because it doesn't allow for 2 or more defines at once.
+//Please leave Sumo _AND_ Bullet enabled
+#define USE_SUMO_SOLID
+#define USE_BULLET
+
+//#define USE_ODE
+
+//on visual studio 7/8, always enable BULLET for now
+//you can have multiple physics engines running anyway, and
+//the scons build system doesn't really support this at the moment.
+//if you got troubles, just comment out USE_BULLET
+#if 1300 <= _MSC_VER
+#define USE_BULLET
+#endif
+
+class RAS_MeshObject;
+class KX_Scene;
+
+typedef enum {
+ KX_BOUNDBOX,
+ KX_BOUNDSPHERE,
+ KX_BOUNDCYLINDER,
+ KX_BOUNDCONE,
+ KX_BOUNDMESH,
+ KX_BOUNDPOLYTOPE,
+ KX_BOUND_DYN_MESH
+} KX_BoundBoxClass;
+
+struct KX_BoxBounds
+{
+ float m_center[3];
+ float m_extends[3];
+};
+
+/* Cone/Cylinder */
+struct KX_CBounds
+{
+ float m_radius;
+ float m_height;
+};
+
+
+struct KX_ObjectProperties
+{
+ bool m_dyna;
+ double m_radius;
+ bool m_angular_rigidbody;
+ bool m_in_active_layer;
+ bool m_ghost;
+ class KX_GameObject* m_dynamic_parent;
+ bool m_isactor;
+ bool m_concave;
+ bool m_isdeformable;
+ bool m_disableSleeping;
+ bool m_hasCompoundChildren;
+ bool m_isCompoundChild;
+ KX_BoundBoxClass m_boundclass;
+ union {
+ KX_BoxBounds box;
+ KX_CBounds c;
+ } m_boundobject;
+};
+
+#ifdef USE_ODE
+
+
+void KX_ConvertODEEngineObject(KX_GameObject* gameobj,
+ RAS_MeshObject* meshobj,
+ KX_Scene* kxscene,
+ struct PHY_ShapeProps* shapeprops,
+ struct PHY_MaterialProps* smmaterial,
+ struct KX_ObjectProperties* objprop);
+
+
+#endif //USE_ODE
+
+
+void KX_ConvertDynamoObject(KX_GameObject* gameobj,
+ RAS_MeshObject* meshobj,
+ KX_Scene* kxscene,
+ struct PHY_ShapeProps* shapeprops,
+ struct PHY_MaterialProps* smmaterial,
+ struct KX_ObjectProperties* objprop);
+
+#ifdef USE_SUMO_SOLID
+
+void KX_ConvertSumoObject( class KX_GameObject* gameobj,
+ class RAS_MeshObject* meshobj,
+ class KX_Scene* kxscene,
+ struct PHY_ShapeProps* shapeprops,
+ struct PHY_MaterialProps* smmaterial,
+ struct KX_ObjectProperties* objprop);
+
+void KX_ClearSumoSharedShapes();
+bool KX_ReInstanceShapeFromMesh(RAS_MeshObject* meshobj);
+
+#endif
+
+#ifdef USE_BULLET
+
+void KX_ConvertBulletObject( class KX_GameObject* gameobj,
+ class RAS_MeshObject* meshobj,
+ class KX_Scene* kxscene,
+ struct PHY_ShapeProps* shapeprops,
+ struct PHY_MaterialProps* smmaterial,
+ struct KX_ObjectProperties* objprop);
+
+void KX_ClearBulletSharedShapes();
+//bool KX_ReInstanceShapeFromMesh(RAS_MeshObject* meshobj);
+
+#endif
+#endif //KX_CONVERTPHYSICSOBJECTS
+
diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp
new file mode 100644
index 00000000000..6ea13f3a5e3
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp
@@ -0,0 +1,1205 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 : 4786)
+#endif
+
+#include "MT_assert.h"
+
+// defines USE_ODE to choose physics engine
+#include "KX_ConvertPhysicsObject.h"
+#include "KX_GameObject.h"
+#include "RAS_MeshObject.h"
+#include "KX_Scene.h"
+#include "SYS_System.h"
+
+#include "PHY_Pro.h" //todo cleanup
+#include "KX_ClientObjectInfo.h"
+
+#include "GEN_Map.h"
+#include "GEN_HashedPtr.h"
+
+#include "KX_PhysicsEngineEnums.h"
+#include "PHY_Pro.h"
+
+#include "KX_MotionState.h" // bridge between motionstate and scenegraph node
+
+#ifdef USE_ODE
+
+#include "KX_OdePhysicsController.h"
+#include "OdePhysicsEnvironment.h"
+#endif //USE_ODE
+
+
+// USE_SUMO_SOLID is defined in headerfile KX_ConvertPhysicsObject.h
+#ifdef USE_SUMO_SOLID
+
+
+#include "SumoPhysicsEnvironment.h"
+#include "KX_SumoPhysicsController.h"
+
+
+// sumo physics specific
+#include "SM_Object.h"
+#include "SM_FhObject.h"
+#include "SM_Scene.h"
+#include "SM_ClientObjectInfo.h"
+
+#include "KX_SumoPhysicsController.h"
+
+struct KX_PhysicsInstance
+{
+ DT_VertexBaseHandle m_vertexbase;
+ int m_vtxarray;
+ RAS_IPolyMaterial* m_material;
+
+ KX_PhysicsInstance(DT_VertexBaseHandle vertex_base, int vtxarray, RAS_IPolyMaterial* mat)
+ : m_vertexbase(vertex_base),
+ m_vtxarray(vtxarray),
+ m_material(mat)
+ {
+ }
+
+ ~KX_PhysicsInstance()
+ {
+ DT_DeleteVertexBase(m_vertexbase);
+ }
+};
+
+static GEN_Map<GEN_HashedPtr,DT_ShapeHandle> map_gamemesh_to_sumoshape;
+static GEN_Map<GEN_HashedPtr, KX_PhysicsInstance*> map_gamemesh_to_instance;
+
+// forward declarations
+static void BL_RegisterSumoObject(KX_GameObject* gameobj,class SM_Scene* sumoScene,class SM_Object* sumoObj,const STR_String& matname,bool isDynamic,bool isActor);
+static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope);
+
+void KX_ConvertSumoObject( KX_GameObject* gameobj,
+ RAS_MeshObject* meshobj,
+ KX_Scene* kxscene,
+ PHY_ShapeProps* kxshapeprops,
+ PHY_MaterialProps* kxmaterial,
+ struct KX_ObjectProperties* objprop)
+
+
+{
+ SM_ShapeProps* smprop = new SM_ShapeProps;
+
+ smprop->m_ang_drag = kxshapeprops->m_ang_drag;
+ smprop->m_do_anisotropic = kxshapeprops->m_do_anisotropic;
+ smprop->m_do_fh = kxshapeprops->m_do_fh;
+ smprop->m_do_rot_fh = kxshapeprops->m_do_rot_fh ;
+ smprop->m_friction_scaling[0] = kxshapeprops->m_friction_scaling[0];
+ smprop->m_friction_scaling[1] = kxshapeprops->m_friction_scaling[1];
+ smprop->m_friction_scaling[2] = kxshapeprops->m_friction_scaling[2];
+ smprop->m_inertia = MT_Vector3(1., 1., 1.) * kxshapeprops->m_inertia;
+ smprop->m_lin_drag = kxshapeprops->m_lin_drag;
+ smprop->m_mass = kxshapeprops->m_mass;
+ smprop->m_radius = objprop->m_radius;
+
+
+ SM_MaterialProps* smmaterial = new SM_MaterialProps;
+
+ smmaterial->m_fh_damping = kxmaterial->m_fh_damping;
+ smmaterial->m_fh_distance = kxmaterial->m_fh_distance;
+ smmaterial->m_fh_normal = kxmaterial->m_fh_normal;
+ smmaterial->m_fh_spring = kxmaterial->m_fh_spring;
+ smmaterial->m_friction = kxmaterial->m_friction;
+ smmaterial->m_restitution = kxmaterial->m_restitution;
+
+ SumoPhysicsEnvironment* sumoEnv =
+ (SumoPhysicsEnvironment*)kxscene->GetPhysicsEnvironment();
+
+ SM_Scene* sceneptr = sumoEnv->GetSumoScene();
+
+ SM_Object* sumoObj=NULL;
+
+ if (objprop->m_dyna && objprop->m_isactor)
+ {
+ DT_ShapeHandle shape = NULL;
+ bool polytope = false;
+ switch (objprop->m_boundclass)
+ {
+ case KX_BOUNDBOX:
+ shape = DT_NewBox(objprop->m_boundobject.box.m_extends[0],
+ objprop->m_boundobject.box.m_extends[1],
+ objprop->m_boundobject.box.m_extends[2]);
+ smprop->m_inertia.scale(objprop->m_boundobject.box.m_extends[0]*objprop->m_boundobject.box.m_extends[0],
+ objprop->m_boundobject.box.m_extends[1]*objprop->m_boundobject.box.m_extends[1],
+ objprop->m_boundobject.box.m_extends[2]*objprop->m_boundobject.box.m_extends[2]);
+ smprop->m_inertia *= smprop->m_mass/MT_Vector3(objprop->m_boundobject.box.m_extends).length();
+ break;
+ case KX_BOUNDCYLINDER:
+ shape = DT_NewCylinder(smprop->m_radius, objprop->m_boundobject.c.m_height);
+ smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius,
+ smprop->m_mass*smprop->m_radius*smprop->m_radius,
+ smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height);
+ break;
+ case KX_BOUNDCONE:
+ shape = DT_NewCone(objprop->m_radius, objprop->m_boundobject.c.m_height);
+ smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius,
+ smprop->m_mass*smprop->m_radius*smprop->m_radius,
+ smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height);
+ break;
+ /* Dynamic mesh objects. WARNING! slow. */
+ case KX_BOUNDPOLYTOPE:
+ polytope = true;
+ // fall through
+ case KX_BOUNDMESH:
+ if (meshobj && meshobj->NumPolygons() > 0)
+ {
+ if ((shape = CreateShapeFromMesh(meshobj, polytope)))
+ {
+ // TODO: calculate proper inertia
+ smprop->m_inertia *= smprop->m_mass*smprop->m_radius*smprop->m_radius;
+ break;
+ }
+ }
+ /* If CreateShapeFromMesh fails, fall through and use sphere */
+ default:
+ case KX_BOUNDSPHERE:
+ shape = DT_NewSphere(objprop->m_radius);
+ smprop->m_inertia *= smprop->m_mass*smprop->m_radius*smprop->m_radius;
+ break;
+
+ }
+
+ sumoObj = new SM_Object(shape, !objprop->m_ghost?smmaterial:NULL,smprop,NULL);
+
+ sumoObj->setRigidBody(objprop->m_angular_rigidbody?true:false);
+
+ BL_RegisterSumoObject(gameobj,sceneptr,sumoObj,"",true, true);
+
+ }
+ else {
+ // non physics object
+ if (meshobj)
+ {
+ int numpolys = meshobj->NumPolygons();
+ {
+
+ DT_ShapeHandle complexshape=0;
+ bool polytope = false;
+
+ switch (objprop->m_boundclass)
+ {
+ case KX_BOUNDBOX:
+ complexshape = DT_NewBox(objprop->m_boundobject.box.m_extends[0], objprop->m_boundobject.box.m_extends[1], objprop->m_boundobject.box.m_extends[2]);
+ break;
+ case KX_BOUNDSPHERE:
+ complexshape = DT_NewSphere(objprop->m_boundobject.c.m_radius);
+ break;
+ case KX_BOUNDCYLINDER:
+ complexshape = DT_NewCylinder(objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_height);
+ break;
+ case KX_BOUNDCONE:
+ complexshape = DT_NewCone(objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_height);
+ break;
+ case KX_BOUNDPOLYTOPE:
+ polytope = true;
+ // fall through
+ default:
+ case KX_BOUNDMESH:
+ if (numpolys>0)
+ {
+ complexshape = CreateShapeFromMesh(meshobj, polytope);
+ //std::cout << "Convert Physics Mesh: " << meshobj->GetName() << std::endl;
+/* if (!complexshape)
+ {
+ // Something has to be done here - if the object has no polygons, it will not be able to have
+ // sensors attached to it.
+ DT_Vector3 pt = {0., 0., 0.};
+ complexshape = DT_NewSphere(1.0);
+ objprop->m_ghost = evilObject = true;
+ } */
+ }
+ break;
+ }
+
+ if (complexshape)
+ {
+ SM_Object *dynamicParent = NULL;
+
+ if (objprop->m_dynamic_parent)
+ {
+ // problem is how to find the dynamic parent
+ // in the scenegraph
+ KX_SumoPhysicsController* sumoctrl =
+ (KX_SumoPhysicsController*)
+ objprop->m_dynamic_parent->GetPhysicsController();
+
+ if (sumoctrl)
+ {
+ dynamicParent = sumoctrl->GetSumoObject();
+ }
+
+ MT_assert(dynamicParent);
+ }
+
+
+ sumoObj = new SM_Object(complexshape,!objprop->m_ghost?smmaterial:NULL,NULL, dynamicParent);
+ const STR_String& matname=meshobj->GetMaterialName(0);
+
+
+ BL_RegisterSumoObject(gameobj,sceneptr,
+ sumoObj,
+ matname,
+ objprop->m_dyna,
+ objprop->m_isactor);
+ }
+ }
+ }
+ }
+
+ // physics object get updated here !
+
+
+ // lazy evaluation because we might not support scaling !gameobj->UpdateTransform();
+
+ if (objprop->m_in_active_layer && sumoObj)
+ {
+ sceneptr->add(*sumoObj);
+ }
+
+}
+
+
+
+static void BL_RegisterSumoObject(
+ KX_GameObject* gameobj,
+ class SM_Scene* sumoScene,
+ class SM_Object* sumoObj,
+ const STR_String& matname,
+ bool isDynamic,
+ bool isActor)
+{
+ PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
+
+ // need easy access, not via 'node' etc.
+ KX_SumoPhysicsController* physicscontroller = new KX_SumoPhysicsController(sumoScene,sumoObj,motionstate,isDynamic);
+ gameobj->SetPhysicsController(physicscontroller,isDynamic);
+
+
+ if (!gameobj->getClientInfo())
+ std::cout << "BL_RegisterSumoObject: WARNING: Object " << gameobj->GetName() << " has no client info" << std::endl;
+ physicscontroller->setNewClientInfo(gameobj->getClientInfo());
+
+
+ gameobj->GetSGNode()->AddSGController(physicscontroller);
+
+ gameobj->getClientInfo()->m_type = (isActor ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC);
+
+ // store materialname in auxinfo, needed for touchsensors
+ gameobj->getClientInfo()->m_auxilary_info = (matname.Length() ? (void*)(matname.ReadPtr()+2) : NULL);
+
+ physicscontroller->SetObject(gameobj->GetSGNode());
+}
+
+static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, int vtxarray, RAS_IPolyMaterial *mat)
+{
+ // instance a mesh from a single vertex array & material
+ const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(mat)[vtxarray])[0]);
+ //const KX_IndexArray &index_array = *meshobj->GetIndexCache(mat)[vtxarray];
+ DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getLocalXYZ(), sizeof(RAS_TexVert));
+
+ DT_ShapeHandle shape = DT_NewComplexShape(vertex_base);
+
+ std::vector<DT_Index> indices;
+ for (int p = 0; p < meshobj->NumPolygons(); p++)
+ {
+ RAS_Polygon* poly = meshobj->GetPolygon(p);
+
+ // only add polygons that have the collisionflag set
+ if (poly->IsCollider())
+ {
+ DT_VertexIndices(3, poly->GetVertexIndexBase().m_indexarray);
+
+ // tesselate
+ if (poly->VertexCount() == 4)
+ {
+ DT_Begin();
+ DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[0]);
+ DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[2]);
+ DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[3]);
+ DT_End();
+ }
+ }
+ }
+
+ //DT_VertexIndices(indices.size(), &indices[0]);
+ DT_EndComplexShape();
+
+ map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, vtxarray, mat));
+ return shape;
+}
+
+static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, int vtxarray, RAS_IPolyMaterial *mat)
+{
+ // instance a mesh from a single vertex array & material
+ const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(mat)[vtxarray])[0]);
+ //const KX_IndexArray &index_array = *meshobj->GetIndexCache(mat)[vtxarray];
+ DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getLocalXYZ(), sizeof(RAS_TexVert));
+
+ std::vector<DT_Index> indices;
+ for (int p = 0; p < meshobj->NumPolygons(); p++)
+ {
+ RAS_Polygon* poly = meshobj->GetPolygon(p);
+
+ // only add polygons that have the collisionflag set
+ if (poly->IsCollider())
+ {
+ indices.push_back(poly->GetVertexIndexBase().m_indexarray[0]);
+ indices.push_back(poly->GetVertexIndexBase().m_indexarray[1]);
+ indices.push_back(poly->GetVertexIndexBase().m_indexarray[2]);
+
+ if (poly->VertexCount() == 4)
+ indices.push_back(poly->GetVertexIndexBase().m_indexarray[3]);
+ }
+ }
+
+ DT_ShapeHandle shape = DT_NewPolytope(vertex_base);
+ DT_VertexIndices(indices.size(), &indices[0]);
+ DT_EndPolytope();
+
+ map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, vtxarray, mat));
+ return shape;
+}
+
+// This will have to be a method in a class somewhere...
+// Update SOLID with a changed physics mesh.
+// not used... yet.
+bool KX_ReInstanceShapeFromMesh(RAS_MeshObject* meshobj)
+{
+ KX_PhysicsInstance *instance = *map_gamemesh_to_instance[GEN_HashedPtr(meshobj)];
+ if (instance)
+ {
+ const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(instance->m_material)[instance->m_vtxarray])[0]);
+ DT_ChangeVertexBase(instance->m_vertexbase, vertex_array[0].getLocalXYZ());
+ return true;
+ }
+ return false;
+}
+
+static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope)
+{
+
+ DT_ShapeHandle *shapeptr = map_gamemesh_to_sumoshape[GEN_HashedPtr(meshobj)];
+ // Mesh has already been converted: reuse
+ if (shapeptr)
+ {
+ return *shapeptr;
+ }
+
+ // Mesh has no polygons!
+ int numpolys = meshobj->NumPolygons();
+ if (!numpolys)
+ {
+ return NULL;
+ }
+
+ // Count the number of collision polygons and check they all come from the same
+ // vertex array
+ int numvalidpolys = 0;
+ int vtxarray = -1;
+ RAS_IPolyMaterial *poly_material = NULL;
+ bool reinstance = true;
+
+ for (int p=0; p<numpolys; p++)
+ {
+ RAS_Polygon* poly = meshobj->GetPolygon(p);
+
+ // only add polygons that have the collisionflag set
+ if (poly->IsCollider())
+ {
+ // check polygon is from the same vertex array
+ if (poly->GetVertexIndexBase().m_vtxarray != vtxarray)
+ {
+ if (vtxarray < 0)
+ vtxarray = poly->GetVertexIndexBase().m_vtxarray;
+ else
+ {
+ reinstance = false;
+ vtxarray = -1;
+ }
+ }
+
+ // check poly is from the same material
+ if (poly->GetMaterial()->GetPolyMaterial() != poly_material)
+ {
+ if (poly_material)
+ {
+ reinstance = false;
+ poly_material = NULL;
+ }
+ else
+ poly_material = poly->GetMaterial()->GetPolyMaterial();
+ }
+
+ // count the number of collision polys
+ numvalidpolys++;
+
+ // We have one collision poly, and we can't reinstance, so we
+ // might as well break here.
+ if (!reinstance)
+ break;
+ }
+ }
+
+ // No collision polygons
+ if (numvalidpolys < 1)
+ return NULL;
+
+ DT_ShapeHandle shape;
+ if (reinstance)
+ {
+ if (polytope)
+ shape = InstancePhysicsPolytope(meshobj, vtxarray, poly_material);
+ else
+ shape = InstancePhysicsComplex(meshobj, vtxarray, poly_material);
+ }
+ else
+ {
+ if (polytope)
+ {
+ std::cout << "CreateShapeFromMesh: " << meshobj->GetName() << " is not suitable for polytope." << std::endl;
+ if (!poly_material)
+ std::cout << " Check mesh materials." << std::endl;
+ if (vtxarray < 0)
+ std::cout << " Check number of vertices." << std::endl;
+ }
+
+ shape = DT_NewComplexShape(NULL);
+
+ numvalidpolys = 0;
+
+ for (int p2=0; p2<numpolys; p2++)
+ {
+ RAS_Polygon* poly = meshobj->GetPolygon(p2);
+
+ // only add polygons that have the collisionflag set
+ if (poly->IsCollider())
+ { /* We have to tesselate here because SOLID can only raycast triangles */
+ DT_Begin();
+ /* V1 */
+ DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[2],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
+ /* V2 */
+ DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[1],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
+ /* V3 */
+ DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[0],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
+
+ numvalidpolys++;
+ DT_End();
+
+ if (poly->VertexCount() == 4)
+ {
+ DT_Begin();
+ /* V1 */
+ DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[3],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
+ /* V3 */
+ DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[2],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
+ /* V4 */
+ DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[0],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
+
+ numvalidpolys++;
+ DT_End();
+ }
+
+ }
+ }
+
+ DT_EndComplexShape();
+ }
+
+ if (numvalidpolys > 0)
+ {
+ map_gamemesh_to_sumoshape.insert(GEN_HashedPtr(meshobj),shape);
+ return shape;
+ }
+
+ delete shape;
+ return NULL;
+}
+
+void KX_ClearSumoSharedShapes()
+{
+ int numshapes = map_gamemesh_to_sumoshape.size();
+ int i;
+ for (i=0;i<numshapes ;i++)
+ {
+ DT_ShapeHandle shape = *map_gamemesh_to_sumoshape.at(i);
+ DT_DeleteShape(shape);
+ }
+
+ map_gamemesh_to_sumoshape.clear();
+
+ for (i=0; i < map_gamemesh_to_instance.size(); i++)
+ delete *map_gamemesh_to_instance.at(i);
+
+ map_gamemesh_to_instance.clear();
+}
+
+
+
+
+
+#endif //USE_SUMO_SOLID
+
+
+#ifdef USE_ODE
+
+void KX_ConvertODEEngineObject(KX_GameObject* gameobj,
+ RAS_MeshObject* meshobj,
+ KX_Scene* kxscene,
+ struct PHY_ShapeProps* shapeprops,
+ struct PHY_MaterialProps* smmaterial,
+ struct KX_ObjectProperties* objprop)
+{
+
+ // not yet, future extension :)
+ bool dyna=objprop->m_dyna;
+ bool fullRigidBody= ( objprop->m_dyna && objprop->m_angular_rigidbody) != 0;
+ bool phantom = objprop->m_ghost;
+ class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
+
+ class ODEPhysicsEnvironment* odeEnv =
+ (ODEPhysicsEnvironment*)kxscene->GetPhysicsEnvironment();
+
+ dxSpace* space = odeEnv->GetOdeSpace();
+ dxWorld* world = odeEnv->GetOdeWorld();
+
+ bool isSphere = false;
+
+ switch (objprop->m_boundclass)
+ {
+ case KX_BOUNDBOX:
+ {
+
+ KX_OdePhysicsController* physicscontroller =
+ new KX_OdePhysicsController(
+ dyna,
+ fullRigidBody,
+ phantom,
+ motionstate,
+ space,
+ world,
+ shapeprops->m_mass,
+ smmaterial->m_friction,
+ smmaterial->m_restitution,
+ isSphere,
+ objprop->m_boundobject.box.m_center,
+ objprop->m_boundobject.box.m_extends,
+ objprop->m_boundobject.c.m_radius
+ );
+
+ gameobj->SetPhysicsController(physicscontroller);
+ physicscontroller->setNewClientInfo(gameobj->getClientInfo());
+ gameobj->GetSGNode()->AddSGController(physicscontroller);
+
+ bool isActor = objprop->m_isactor;
+ STR_String materialname;
+ if (meshobj)
+ materialname = meshobj->GetMaterialName(0);
+
+ const char* matname = materialname.ReadPtr();
+
+
+ physicscontroller->SetObject(gameobj->GetSGNode());
+
+ break;
+ }
+ default:
+ {
+ }
+ };
+
+}
+
+
+#endif // USE_ODE
+
+
+#ifdef USE_BULLET
+
+#include "CcdPhysicsEnvironment.h"
+#include "CcdPhysicsController.h"
+#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
+
+#include "KX_BulletPhysicsController.h"
+#include "btBulletDynamicsCommon.h"
+
+ #ifdef WIN32
+#if _MSC_VER >= 1310
+//only use SIMD Hull code under Win32
+//#define TEST_HULL 1
+#ifdef TEST_HULL
+#define USE_HULL 1
+//#define TEST_SIMD_HULL 1
+
+#include "NarrowPhaseCollision/Hull.h"
+#endif //#ifdef TEST_HULL
+
+#endif //_MSC_VER
+#endif //WIN32
+
+
+static GEN_Map<GEN_HashedPtr,btCollisionShape*> map_gamemesh_to_bulletshape;
+
+// forward declarations
+static btCollisionShape* CreateBulletShapeFromMesh(RAS_MeshObject* meshobj, bool polytope)
+{
+ if (!meshobj)
+ return 0;
+
+ btCollisionShape* collisionMeshShape = 0;
+ btConvexHullShape* convexHullShape = 0;
+ btTriangleMeshShape* concaveShape = 0;
+
+ btTriangleMesh* collisionMeshData = 0;
+
+ //see if there is any polygons, if not, bail out.
+
+ int numPoints = 0;
+ btVector3* points = 0;
+
+ btCollisionShape** shapeptr = map_gamemesh_to_bulletshape[GEN_HashedPtr(meshobj)];
+
+ // Mesh has already been converted: reuse
+ if (shapeptr)
+ {
+ //return *shapeptr;
+ }
+
+ // Mesh has no polygons!
+ int numpolys = meshobj->NumPolygons();
+ if (!numpolys)
+ {
+ return NULL;
+ }
+
+ // Count the number of collision polygons and check they all come from the same
+ // vertex array
+ int numvalidpolys = 0;
+ int vtxarray = -1;
+ RAS_IPolyMaterial *poly_material = NULL;
+ bool reinstance = true;
+
+ for (int p=0; p<numpolys; p++)
+ {
+ RAS_Polygon* poly = meshobj->GetPolygon(p);
+
+ // only add polygons that have the collisionflag set
+ if (poly->IsCollider())
+ {
+ // check polygon is from the same vertex array
+ if (poly->GetVertexIndexBase().m_vtxarray != vtxarray)
+ {
+ if (vtxarray < 0)
+ vtxarray = poly->GetVertexIndexBase().m_vtxarray;
+ else
+ {
+ reinstance = false;
+ vtxarray = -1;
+ }
+ }
+
+ // check poly is from the same material
+ if (poly->GetMaterial()->GetPolyMaterial() != poly_material)
+ {
+ if (poly_material)
+ {
+ reinstance = false;
+ poly_material = NULL;
+ }
+ else
+ poly_material = poly->GetMaterial()->GetPolyMaterial();
+ }
+
+ // count the number of collision polys
+ numvalidpolys++;
+
+ // We have one collision poly, and we can't reinstance, so we
+ // might as well break here.
+ if (!reinstance)
+ break;
+ }
+ }
+
+ // No collision polygons
+ if (numvalidpolys < 1)
+ return NULL;
+
+
+ if (polytope)
+ {
+ convexHullShape = new btConvexHullShape(&points[0].getX(),numPoints);
+ collisionMeshShape = convexHullShape;
+ } else
+ {
+ collisionMeshData = new btTriangleMesh();
+// concaveShape = new btTriangleMeshShape(collisionMeshData);
+ //collisionMeshShape = concaveShape;
+
+ }
+
+
+ numvalidpolys = 0;
+
+ for (int p2=0; p2<numpolys; p2++)
+ {
+ RAS_Polygon* poly = meshobj->GetPolygon(p2);
+
+ // only add polygons that have the collisionflag set
+ if (poly->IsCollider())
+ {
+ //Bullet can raycast any shape, so
+ if (polytope)
+ {
+ for (int i=0;i<poly->VertexCount();i++)
+ {
+ const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[i],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+ btPoint3 point(vtx[0],vtx[1],vtx[2]);
+ convexHullShape->addPoint(point);
+ }
+ if (poly->VertexCount())
+ numvalidpolys++;
+
+ } else
+ {
+ {
+ const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[2],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+ btPoint3 vertex0(vtx[0],vtx[1],vtx[2]);
+ vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[1],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+ btPoint3 vertex1(vtx[0],vtx[1],vtx[2]);
+ vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[0],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+ btPoint3 vertex2(vtx[0],vtx[1],vtx[2]);
+ collisionMeshData->addTriangle(vertex0,vertex1,vertex2);
+ numvalidpolys++;
+ }
+ if (poly->VertexCount() == 4)
+ {
+ const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[3],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+ btPoint3 vertex0(vtx[0],vtx[1],vtx[2]);
+ vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[2],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+ btPoint3 vertex1(vtx[0],vtx[1],vtx[2]);
+ vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[0],
+ poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+ btPoint3 vertex2(vtx[0],vtx[1],vtx[2]);
+ collisionMeshData->addTriangle(vertex0,vertex1,vertex2);
+ numvalidpolys++;
+ }
+
+ }
+ }
+ }
+
+
+
+ if (numvalidpolys > 0)
+ {
+
+ //map_gamemesh_to_bulletshape.insert(GEN_HashedPtr(meshobj),collisionMeshShape);
+ if (!polytope)
+ {
+ bool useQuantization = true;
+ concaveShape = new btBvhTriangleMeshShape( collisionMeshData, useQuantization );
+ //concaveShape = new btTriangleMeshShape( collisionMeshData );
+
+ concaveShape->recalcLocalAabb();
+ collisionMeshShape = concaveShape;
+
+ }
+
+
+
+ return collisionMeshShape;
+ }
+
+ delete collisionMeshShape;
+ return NULL;
+
+}
+
+
+void KX_ConvertBulletObject( class KX_GameObject* gameobj,
+ class RAS_MeshObject* meshobj,
+ class KX_Scene* kxscene,
+ struct PHY_ShapeProps* shapeprops,
+ struct PHY_MaterialProps* smmaterial,
+ struct KX_ObjectProperties* objprop)
+{
+
+ CcdPhysicsEnvironment* env = (CcdPhysicsEnvironment*)kxscene->GetPhysicsEnvironment();
+ assert(env);
+
+
+ bool isbulletdyna = false;
+ CcdConstructionInfo ci;
+ class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
+
+
+
+ if (!objprop->m_dyna)
+ {
+ ci.m_collisionFlags |= btCollisionObject::CF_STATIC_OBJECT;
+ }
+
+ ci.m_MotionState = motionstate;
+ ci.m_gravity = btVector3(0,0,0);
+ ci.m_localInertiaTensor =btVector3(0,0,0);
+ ci.m_mass = objprop->m_dyna ? shapeprops->m_mass : 0.f;
+ isbulletdyna = objprop->m_dyna;
+
+ ci.m_localInertiaTensor = btVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f);
+
+ btTransform trans;
+ trans.setIdentity();
+
+ btCollisionShape* bm = 0;
+
+ switch (objprop->m_boundclass)
+ {
+ case KX_BOUNDSPHERE:
+ {
+ float radius = objprop->m_radius;
+ btVector3 inertiaHalfExtents (
+ radius,
+ radius,
+ radius);
+
+ //blender doesn't support multisphere, but for testing:
+
+ //bm = new MultiSphereShape(inertiaHalfExtents,,&trans.getOrigin(),&radius,1);
+ bm = new btSphereShape(objprop->m_radius);
+ bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+ break;
+ };
+ case KX_BOUNDBOX:
+ {
+ MT_Vector3 halfExtents (
+ objprop->m_boundobject.box.m_extends[0],
+ objprop->m_boundobject.box.m_extends[1],
+ objprop->m_boundobject.box.m_extends[2]);
+
+ halfExtents /= 2.f;
+
+ //btVector3 he (halfExtents[0]-CONVEX_DISTANCE_MARGIN ,halfExtents[1]-CONVEX_DISTANCE_MARGIN ,halfExtents[2]-CONVEX_DISTANCE_MARGIN );
+ //he = he.absolute();
+
+ btVector3 he (halfExtents[0],halfExtents[1],halfExtents[2]);
+ he = he.absolute();
+
+
+ bm = new btBoxShape(he);
+ bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+ break;
+ };
+ case KX_BOUNDCYLINDER:
+ {
+ btVector3 halfExtents (
+ objprop->m_boundobject.c.m_radius,
+ objprop->m_boundobject.c.m_radius,
+ objprop->m_boundobject.c.m_height * 0.5f
+ );
+ bm = new btCylinderShapeZ(halfExtents);
+ bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+
+ break;
+ }
+
+ case KX_BOUNDCONE:
+ {
+ btVector3 halfExtents (objprop->m_boundobject.box.m_extends[0],
+ objprop->m_boundobject.box.m_extends[1],
+ objprop->m_boundobject.box.m_extends[2]);
+
+
+ halfExtents /= 2.f;
+
+ bm = new btConeShapeZ(objprop->m_boundobject.c.m_radius,objprop->m_boundobject.c.m_height);
+ bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+
+ break;
+ }
+ case KX_BOUNDPOLYTOPE:
+ {
+ bm = CreateBulletShapeFromMesh(meshobj,true);
+ if (bm)
+ {
+ bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+ }
+ break;
+ }
+ case KX_BOUNDMESH:
+ {
+ if (!ci.m_mass)
+ {
+ bm = CreateBulletShapeFromMesh(meshobj,false);
+ ci.m_localInertiaTensor.setValue(0.f,0.f,0.f);
+ //no moving concave meshes, so don't bother calculating inertia
+ //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+ }
+
+ break;
+ }
+
+ default:
+ //interpret the shape as a concave triangle-mesh
+ {
+ if (meshobj)
+ {
+ bm = CreateBulletShapeFromMesh(meshobj,false);
+ ci.m_localInertiaTensor.setValue(0.f,0.f,0.f);
+
+ // assert(0);
+
+ /*
+ meshobj->ScheduleCollisionPolygons();
+
+ KX_DeformableMesh* gfxmesh = new KX_DeformableMesh(meshobj);
+ gfxmesh->sendFixedMapping();
+ //trianglemesh
+ bm = new TriangleMeshInterface(gfxmesh,trans);
+ */
+ }
+ }
+ }
+
+
+// ci.m_localInertiaTensor.setValue(0.1f,0.1f,0.1f);
+
+ if (!bm)
+ return;
+
+ bm->setMargin(0.06);
+
+
+
+ if (objprop->m_isCompoundChild)
+ {
+ //find parent, compound shape and add to it
+ //take relative transform into account!
+ KX_BulletPhysicsController* parentCtrl = (KX_BulletPhysicsController*)objprop->m_dynamic_parent->GetPhysicsController();
+ assert(parentCtrl);
+ btRigidBody* rigidbody = parentCtrl->GetRigidBody();
+ btCollisionShape* colShape = rigidbody->getCollisionShape();
+ assert(colShape->isCompound());
+ btCompoundShape* compoundShape = (btCompoundShape*)colShape;
+ btTransform childTrans;
+ childTrans.setIdentity();
+ NodeList& children = objprop->m_dynamic_parent->GetSGNode()->GetSGChildren();
+
+ MT_Point3 childPos = gameobj->GetSGNode()->GetLocalPosition();
+ MT_Matrix3x3 childRot = gameobj->GetSGNode()->GetLocalOrientation();
+ MT_Vector3 childScale = gameobj->GetSGNode()->GetLocalScale();
+
+ bm->setLocalScaling(btVector3(childScale.x(),childScale.y(),childScale.z()));
+ childTrans.setOrigin(btVector3(childPos.x(),childPos.y(),childPos.z()));
+ float rotval[12];
+ childRot.getValue(rotval);
+ btMatrix3x3 newRot;
+ newRot.setValue(rotval[0],rotval[1],rotval[2],rotval[4],rotval[5],rotval[6],rotval[8],rotval[9],rotval[10]);
+ newRot = newRot.transpose();
+
+ childTrans.setBasis(newRot);
+
+
+ compoundShape->addChildShape(childTrans,bm);
+ //do some recalc?
+ //recalc inertia for rigidbody
+ if (!rigidbody->isStaticOrKinematicObject())
+ {
+ btVector3 localInertia;
+ float mass = 1.f/rigidbody->getInvMass();
+ compoundShape->calculateLocalInertia(mass,localInertia);
+ rigidbody->setMassProps(mass,localInertia);
+ }
+ return;
+ }
+
+ if (objprop->m_hasCompoundChildren)
+ {
+ //replace shape by compoundShape
+ btCompoundShape* compoundShape = new btCompoundShape();
+ btTransform identTrans;
+ identTrans.setIdentity();
+ compoundShape->addChildShape(identTrans,bm);
+ bm = compoundShape;
+ }
+
+
+
+
+
+
+#ifdef TEST_SIMD_HULL
+ if (bm->IsPolyhedral())
+ {
+ PolyhedralConvexShape* polyhedron = static_cast<PolyhedralConvexShape*>(bm);
+ if (!polyhedron->m_optionalHull)
+ {
+ //first convert vertices in 'Point3' format
+ int numPoints = polyhedron->GetNumVertices();
+ Point3* points = new Point3[numPoints+1];
+ //first 4 points should not be co-planar, so add central point to satisfy MakeHull
+ points[0] = Point3(0.f,0.f,0.f);
+
+ btVector3 vertex;
+ for (int p=0;p<numPoints;p++)
+ {
+ polyhedron->GetVertex(p,vertex);
+ points[p+1] = Point3(vertex.getX(),vertex.getY(),vertex.getZ());
+ }
+
+ Hull* hull = Hull::MakeHull(numPoints+1,points);
+ polyhedron->m_optionalHull = hull;
+ }
+
+ }
+#endif //TEST_SIMD_HULL
+
+
+ ci.m_collisionShape = bm;
+
+
+
+ ci.m_friction = smmaterial->m_friction;//tweak the friction a bit, so the default 0.5 works nice
+ ci.m_restitution = smmaterial->m_restitution;
+ ci.m_physicsEnv = env;
+ // drag / damping is inverted
+ ci.m_linearDamping = 1.f - shapeprops->m_lin_drag;
+ ci.m_angularDamping = 1.f - shapeprops->m_ang_drag;
+ //need a bit of damping, else system doesn't behave well
+ ci.m_inertiaFactor = shapeprops->m_inertia/0.4f;//defaults to 0.4, don't want to change behaviour
+
+ KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna);
+
+ if (objprop->m_in_active_layer)
+ {
+ env->addCcdPhysicsController( physicscontroller);
+ }
+
+
+
+ gameobj->SetPhysicsController(physicscontroller,isbulletdyna);
+ physicscontroller->setNewClientInfo(gameobj->getClientInfo());
+ btRigidBody* rbody = physicscontroller->GetRigidBody();
+
+ if (objprop->m_disableSleeping)
+ rbody->setActivationState(DISABLE_DEACTIVATION);
+
+ if (objprop->m_ghost)
+ {
+ rbody->setCollisionFlags(rbody->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
+ }
+ if (objprop->m_dyna && !objprop->m_angular_rigidbody)
+ {
+ /*
+ //setting the inertia could achieve similar results to constraint the up
+ //but it is prone to instability, so use special 'Angular' constraint
+ btVector3 inertia = physicscontroller->GetRigidBody()->getInvInertiaDiagLocal();
+ inertia.setX(0.f);
+ inertia.setZ(0.f);
+
+ physicscontroller->GetRigidBody()->setInvInertiaDiagLocal(inertia);
+ physicscontroller->GetRigidBody()->updateInertiaTensor();
+ */
+
+ //env->createConstraint(physicscontroller,0,PHY_ANGULAR_CONSTRAINT,0,0,0,0,0,1);
+ physicscontroller->GetRigidBody()->setAngularFactor(0.f);
+
+ }
+
+ bool isActor = objprop->m_isactor;
+ gameobj->getClientInfo()->m_type = (isActor ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC);
+ // store materialname in auxinfo, needed for touchsensors
+ if (meshobj)
+ {
+ const STR_String& matname=meshobj->GetMaterialName(0);
+ gameobj->getClientInfo()->m_auxilary_info = (matname.Length() ? (void*)(matname.ReadPtr()+2) : NULL);
+ } else
+ {
+ gameobj->getClientInfo()->m_auxilary_info = 0;
+ }
+
+
+ gameobj->GetSGNode()->AddSGController(physicscontroller);
+
+ STR_String materialname;
+ if (meshobj)
+ materialname = meshobj->GetMaterialName(0);
+
+ physicscontroller->SetObject(gameobj->GetSGNode());
+
+}
+
+
+void KX_ClearBulletSharedShapes()
+{
+ int numshapes = map_gamemesh_to_bulletshape.size();
+ int i;
+ btCollisionShape*shape=0;
+ for (i=0;i<numshapes ;i++)
+ {
+ shape = *map_gamemesh_to_bulletshape.at(i);
+ //delete shape;
+ }
+
+ map_gamemesh_to_bulletshape.clear();
+
+}
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_EmptyObject.cpp b/source/gameengine/Ketsji/KX_EmptyObject.cpp
new file mode 100644
index 00000000000..4636f2f0a3e
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_EmptyObject.cpp
@@ -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 *****
+ */
+#include "KX_EmptyObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_EmptyObject::~KX_EmptyObject()
+{
+
+}
diff --git a/source/gameengine/Ketsji/KX_EmptyObject.h b/source/gameengine/Ketsji/KX_EmptyObject.h
new file mode 100644
index 00000000000..46858b5c46d
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_EmptyObject.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 __KX_EMPTYOBJECT
+#define __KX_EMPTYOBJECT
+#include "KX_GameObject.h"
+
+class KX_EmptyObject : public KX_GameObject
+{
+public:
+ KX_EmptyObject(void* sgReplicationInfo,SG_Callbacks callbacks) :
+ KX_GameObject(sgReplicationInfo,callbacks)
+ {};
+ virtual ~KX_EmptyObject();
+
+};
+
+#endif //__KX_EMPTYOBJECT
+
diff --git a/source/gameengine/Ketsji/KX_GameActuator.cpp b/source/gameengine/Ketsji/KX_GameActuator.cpp
new file mode 100644
index 00000000000..1340a9c8497
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_GameActuator.cpp
@@ -0,0 +1,221 @@
+/**
+* global game 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 *****
+*/
+
+#include "SCA_IActuator.h"
+#include "KX_GameActuator.h"
+//#include <iostream>
+#include "KX_Scene.h"
+#include "KX_KetsjiEngine.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+KX_GameActuator::KX_GameActuator(SCA_IObject *gameobj,
+ int mode,
+ const STR_String& filename,
+ const STR_String& loadinganimationname,
+ KX_Scene* scene,
+ KX_KetsjiEngine* ketsjiengine,
+ PyTypeObject* T)
+ : SCA_IActuator(gameobj, T)
+{
+ m_mode = mode;
+ m_filename = filename;
+ m_loadinganimationname = loadinganimationname;
+ m_scene = scene;
+ m_ketsjiengine = ketsjiengine;
+} /* End of constructor */
+
+
+
+KX_GameActuator::~KX_GameActuator()
+{
+ // there's nothing to be done here, really....
+} /* end of destructor */
+
+
+
+CValue* KX_GameActuator::GetReplica()
+{
+ KX_GameActuator* replica = new KX_GameActuator(*this);
+ replica->ProcessReplica();
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+bool KX_GameActuator::Update()
+{
+ // bool result = false; /*unused*/
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (bNegativeEvent)
+ return false; // do nothing on negative events
+
+ switch (m_mode)
+ {
+ case KX_GAME_LOAD:
+ case KX_GAME_START:
+ {
+ if (m_ketsjiengine)
+ {
+ STR_String exitstring = "start other game";
+ m_ketsjiengine->RequestExit(KX_EXIT_REQUEST_START_OTHER_GAME);
+ m_ketsjiengine->SetNameNextGame(m_filename);
+ m_scene->AddDebugProperty((this)->GetParent(), exitstring);
+ }
+
+ break;
+ }
+ case KX_GAME_RESTART:
+ {
+ if (m_ketsjiengine)
+ {
+ STR_String exitstring = "restarting game";
+ m_ketsjiengine->RequestExit(KX_EXIT_REQUEST_RESTART_GAME);
+ m_ketsjiengine->SetNameNextGame(m_filename);
+ m_scene->AddDebugProperty((this)->GetParent(), exitstring);
+ }
+ break;
+ }
+ case KX_GAME_QUIT:
+ {
+ if (m_ketsjiengine)
+ {
+ STR_String exitstring = "quiting game";
+ m_ketsjiengine->RequestExit(KX_EXIT_REQUEST_QUIT_GAME);
+ m_scene->AddDebugProperty((this)->GetParent(), exitstring);
+ }
+ break;
+ }
+ default:
+ ; /* do nothing? this is an internal error !!! */
+ }
+
+ return false;
+}
+
+
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_GameActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_GameActuator",
+ sizeof(KX_GameActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+
+PyParentObject KX_GameActuator::Parents[] =
+{
+ &KX_GameActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+PyMethodDef KX_GameActuator::Methods[] =
+{
+ {"getFile", (PyCFunction) KX_GameActuator::sPyGetFile, METH_VARARGS, GetFile_doc},
+ {"setFile", (PyCFunction) KX_GameActuator::sPySetFile, METH_VARARGS, SetFile_doc},
+ {NULL,NULL} //Sentinel
+};
+
+/* getFile */
+char KX_GameActuator::GetFile_doc[] =
+"getFile()\n"
+"get the name of the file to start.\n";
+PyObject* KX_GameActuator::PyGetFile(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyString_FromString(m_filename);
+}
+
+/* setFile */
+char KX_GameActuator::SetFile_doc[] =
+"setFile(name)\n"
+"set the name of the file to start.\n";
+PyObject* KX_GameActuator::PySetFile(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ char* new_file;
+
+ if (!PyArg_ParseTuple(args, "s", &new_file))
+ {
+ return NULL;
+ }
+
+ m_filename = STR_String(new_file);
+
+ Py_Return;
+
+}
+
+
+
+PyObject* KX_GameActuator::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_IActuator);
+}
+
+
diff --git a/source/gameengine/Ketsji/KX_GameActuator.h b/source/gameengine/Ketsji/KX_GameActuator.h
new file mode 100644
index 00000000000..5da10576dde
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_GameActuator.h
@@ -0,0 +1,88 @@
+
+//
+// actuator for global game 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 __KX_GAMEACTUATOR
+#define __KX_GAMEACTUATOR
+
+#include "SCA_IActuator.h"
+
+class KX_GameActuator : public SCA_IActuator
+{
+ Py_Header;
+protected:
+ int m_mode;
+ bool m_restart;
+ STR_String m_filename;
+ STR_String m_loadinganimationname;
+ class KX_Scene* m_scene;
+ class KX_KetsjiEngine* m_ketsjiengine;
+
+ public:
+ enum KX_GameActuatorMode
+ {
+ KX_GAME_NODEF = 0,
+ KX_GAME_LOAD,
+ KX_GAME_START,
+ KX_GAME_RESTART,
+ KX_GAME_QUIT,
+ KX_GAME_MAX
+
+ };
+
+ KX_GameActuator(SCA_IObject* gameobj,
+ int mode,
+ const STR_String& filename,
+ const STR_String& loadinganimationname,
+ KX_Scene* scene,
+ KX_KetsjiEngine* ketsjiEngine,
+ PyTypeObject* T=&Type);
+ virtual ~KX_GameActuator();
+
+ virtual CValue* GetReplica();
+
+ virtual bool Update();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+ KX_PYMETHOD_DOC(KX_GameActuator,GetFile);
+ KX_PYMETHOD_DOC(KX_GameActuator,SetFile);
+
+}; /* end of class KX_GameActuator */
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
new file mode 100644
index 00000000000..67c82ee2082
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -0,0 +1,1174 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Game object wrapper
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(_WIN64)
+typedef unsigned __int64 uint_ptr;
+#else
+typedef unsigned long uint_ptr;
+#endif
+
+#ifdef WIN32
+// This warning tells us about truncation of __long__ stl-generated names.
+// It can occasionally cause DevStudio to have internal compiler warnings.
+#pragma warning( disable : 4786 )
+#endif
+
+
+#define KX_INERTIA_INFINITE 10000
+#include "RAS_IPolygonMaterial.h"
+#include "KX_BlenderMaterial.h"
+#include "KX_GameObject.h"
+#include "RAS_MeshObject.h"
+#include "KX_MeshProxy.h"
+#include <stdio.h> // printf
+#include "SG_Controller.h"
+#include "KX_IPhysicsController.h"
+#include "SG_Node.h"
+#include "SG_Controller.h"
+#include "KX_ClientObjectInfo.h"
+#include "RAS_BucketManager.h"
+
+#include "KX_PyMath.h"
+
+// This file defines relationships between parents and children
+// in the game engine.
+
+#include "KX_SG_NodeRelationships.h"
+
+KX_GameObject::KX_GameObject(
+ void* sgReplicationInfo,
+ SG_Callbacks callbacks,
+ PyTypeObject* T
+) :
+ SCA_IObject(T),
+ m_bDyna(false),
+ m_bSuspendDynamics(false),
+ m_bUseObjectColor(false),
+ m_bVisible(true),
+ m_pPhysicsController1(NULL),
+ m_isDeformable(false)
+{
+ m_ignore_activity_culling = false;
+ m_pClient_info = new KX_ClientObjectInfo(this, KX_ClientObjectInfo::ACTOR);
+ m_pSGNode = new SG_Node(this,sgReplicationInfo,callbacks);
+
+ // define the relationship between this node and it's parent.
+
+ KX_NormalParentRelation * parent_relation =
+ KX_NormalParentRelation::New();
+ m_pSGNode->SetParentRelation(parent_relation);
+
+
+};
+
+
+
+KX_GameObject::~KX_GameObject()
+{
+ // is this delete somewhere ?
+ //if (m_sumoObj)
+ // delete m_sumoObj;
+ delete m_pClient_info;
+ //if (m_pSGNode)
+ // delete m_pSGNode;
+
+}
+
+
+
+CValue* KX_GameObject:: Calc(VALUE_OPERATOR op, CValue *val)
+{
+ return NULL;
+}
+
+
+
+CValue* KX_GameObject::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val)
+{
+ return NULL;
+}
+
+
+
+const STR_String & KX_GameObject::GetText()
+{
+ return m_text;
+}
+
+
+
+float KX_GameObject::GetNumber()
+{
+ return 0;
+}
+
+
+
+STR_String KX_GameObject::GetName()
+{
+ return m_name;
+}
+
+
+
+void KX_GameObject::SetName(STR_String name)
+{
+ m_name = name;
+}; // Set the name of the value
+
+
+
+void KX_GameObject::ReplicaSetName(STR_String name)
+{
+}
+
+
+
+
+
+
+KX_IPhysicsController* KX_GameObject::GetPhysicsController()
+{
+ return m_pPhysicsController1;
+}
+
+
+
+
+
+KX_GameObject* KX_GameObject::GetParent()
+{
+ KX_GameObject* result = NULL;
+ SG_Node* node = m_pSGNode;
+
+ while (node && !result)
+ {
+ node = node->GetSGParent();
+ if (node)
+ result = (KX_GameObject*)node->GetSGClientObject();
+ }
+
+ if (result)
+ result->AddRef();
+
+ return result;
+
+}
+
+
+
+void KX_GameObject::ProcessReplica(KX_GameObject* replica)
+{
+ replica->m_pPhysicsController1 = NULL;
+ replica->m_pSGNode = NULL;
+ replica->m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info);
+ replica->m_pClient_info->m_gameobject = replica;
+}
+
+
+
+CValue* KX_GameObject::GetReplica()
+{
+ KX_GameObject* replica = new KX_GameObject(*this);
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ ProcessReplica(replica);
+
+ return replica;
+}
+
+
+
+void KX_GameObject::ApplyForce(const MT_Vector3& force,bool local)
+{
+ if (m_pPhysicsController1)
+ m_pPhysicsController1->ApplyForce(force,local);
+}
+
+
+
+void KX_GameObject::ApplyTorque(const MT_Vector3& torque,bool local)
+{
+ if (m_pPhysicsController1)
+ m_pPhysicsController1->ApplyTorque(torque,local);
+}
+
+
+
+void KX_GameObject::ApplyMovement(const MT_Vector3& dloc,bool local)
+{
+ if (m_pPhysicsController1) // (IsDynamic())
+ {
+ m_pPhysicsController1->RelativeTranslate(dloc,local);
+ }
+ GetSGNode()->RelativeTranslate(dloc,GetSGNode()->GetSGParent(),local);
+}
+
+
+
+void KX_GameObject::ApplyRotation(const MT_Vector3& drot,bool local)
+{
+ MT_Matrix3x3 rotmat(drot);
+ rotmat.transpose();
+
+ if (m_pPhysicsController1) // (IsDynamic())
+ m_pPhysicsController1->RelativeRotate(rotmat,local);
+ // in worldspace
+ GetSGNode()->RelativeRotate(rotmat,local);
+}
+
+
+
+/**
+GetOpenGL Matrix, returns an OpenGL 'compatible' matrix
+*/
+double* KX_GameObject::GetOpenGLMatrix()
+{
+ // todo: optimize and only update if necessary
+ double* fl = m_OpenGL_4x4Matrix.getPointer();
+ MT_Transform trans;
+
+ trans.setOrigin(GetSGNode()->GetWorldPosition());
+ trans.setBasis(GetSGNode()->GetWorldOrientation());
+
+ MT_Vector3 scaling = GetSGNode()->GetWorldScaling();
+
+ trans.scale(scaling[0], scaling[1], scaling[2]);
+ trans.getValue(fl);
+
+ return fl;
+}
+
+
+
+void KX_GameObject::Bucketize()
+{
+ double* fl = GetOpenGLMatrix();
+
+ for (size_t i=0;i<m_meshes.size();i++)
+ m_meshes[i]->Bucketize(fl, this, m_bUseObjectColor, m_objectColor);
+}
+
+
+
+void KX_GameObject::RemoveMeshes()
+{
+ double* fl = GetOpenGLMatrix();
+
+ for (size_t i=0;i<m_meshes.size();i++)
+ m_meshes[i]->RemoveFromBuckets(fl, this);
+
+ //note: meshes can be shared, and are deleted by KX_BlenderSceneConverter
+
+ m_meshes.clear();
+}
+
+
+
+void KX_GameObject::UpdateNonDynas()
+{
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->SetSumoTransform(true);
+ }
+}
+
+
+
+void KX_GameObject::UpdateTransform()
+{
+ if (m_pPhysicsController1)
+ m_pPhysicsController1->SetSumoTransform(false);
+}
+
+void KX_GameObject::UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene)
+{
+ ((KX_GameObject*)gameobj)->UpdateTransform();
+}
+
+
+void KX_GameObject::SetDebugColor(unsigned int bgra)
+{
+ for (size_t i=0;i<m_meshes.size();i++)
+ m_meshes[i]->DebugColor(bgra);
+}
+
+
+
+void KX_GameObject::ResetDebugColor()
+{
+ SetDebugColor(0xff000000);
+}
+
+
+
+void KX_GameObject::UpdateIPO(float curframetime,
+ bool recurse,
+ bool ipo_as_force,
+ bool force_local)
+{
+
+ // The ipo-actuator needs a sumo reference... this is retrieved (unfortunately)
+ // by the iposgcontr itself...
+// ipocontr->SetSumoReference(gameobj->GetSumoScene(),
+// gameobj->GetSumoObject());
+
+
+ // The ipo has to be treated as a force, and not a displacement!
+ // For this case, we send some settings to the controller. This
+ // may need some caching...
+ if (ipo_as_force) {
+ SGControllerList::iterator it = GetSGNode()->GetSGControllerList().begin();
+
+ while (it != GetSGNode()->GetSGControllerList().end()) {
+ (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, ipo_as_force);
+ (*it)->SetOption(SG_Controller::SG_CONTR_IPO_FORCES_ACT_LOCAL, force_local);
+ it++;
+ }
+ }
+
+ // The rest is the 'normal' update procedure.
+ GetSGNode()->SetSimulatedTime(curframetime,recurse);
+ GetSGNode()->UpdateWorldData(curframetime);
+ UpdateTransform();
+}
+
+// IPO update
+void
+KX_GameObject::UpdateMaterialData(
+ MT_Vector4 rgba,
+ MT_Vector3 specrgb,
+ MT_Scalar hard,
+ MT_Scalar spec,
+ MT_Scalar ref,
+ MT_Scalar emit,
+ MT_Scalar alpha
+
+ )
+{
+ int mesh = 0;
+ if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) {
+ RAS_MaterialBucket::Set::iterator mit = m_meshes[mesh]->GetFirstMaterial();
+ for(; mit != m_meshes[mesh]->GetLastMaterial(); ++mit)
+ {
+ RAS_IPolyMaterial* poly = (*mit)->GetPolyMaterial();
+ if(poly->GetFlag() & RAS_BLENDERMAT )
+ {
+ SetObjectColor(rgba);
+ KX_BlenderMaterial *m = static_cast<KX_BlenderMaterial*>(poly);
+ m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha);
+ }
+ }
+ }
+}
+bool
+KX_GameObject::GetVisible(
+ void
+ )
+{
+ return m_bVisible;
+}
+
+void
+KX_GameObject::SetVisible(
+ bool v
+ )
+{
+ m_bVisible = v;
+}
+
+// used by Python, and the actuatorshould _not_ be misused by the
+// scene!
+void
+KX_GameObject::MarkVisible(
+ bool visible
+ )
+{
+ /* If explicit visibility settings are used, this is
+ * determined on this level. Maybe change this to mesh level
+ * later on? */
+
+ double* fl = GetOpenGLMatrixPtr()->getPointer();
+ for (size_t i=0;i<m_meshes.size();i++)
+ {
+ m_meshes[i]->MarkVisible(fl,this,visible,m_bUseObjectColor,m_objectColor);
+ }
+}
+
+
+// Always use the flag?
+void
+KX_GameObject::MarkVisible(
+ void
+ )
+{
+ double* fl = GetOpenGLMatrixPtr()->getPointer();
+ for (size_t i=0;i<m_meshes.size();i++)
+ {
+ m_meshes[i]->MarkVisible(fl,
+ this,
+ m_bVisible,
+ m_bUseObjectColor,
+ m_objectColor
+ );
+ }
+}
+
+
+void KX_GameObject::addLinearVelocity(const MT_Vector3& lin_vel,bool local)
+{
+ if (m_pPhysicsController1)
+ m_pPhysicsController1->SetLinearVelocity(lin_vel + m_pPhysicsController1->GetLinearVelocity(),local);
+}
+
+
+
+void KX_GameObject::setLinearVelocity(const MT_Vector3& lin_vel,bool local)
+{
+ if (m_pPhysicsController1)
+ m_pPhysicsController1->SetLinearVelocity(lin_vel,local);
+}
+
+
+
+void KX_GameObject::setAngularVelocity(const MT_Vector3& ang_vel,bool local)
+{
+ if (m_pPhysicsController1)
+ m_pPhysicsController1->SetAngularVelocity(ang_vel,local);
+}
+
+void KX_GameObject::ResolveCombinedVelocities(
+ const MT_Vector3 & lin_vel,
+ const MT_Vector3 & ang_vel,
+ bool lin_vel_local,
+ bool ang_vel_local
+){
+ if (m_pPhysicsController1)
+ {
+
+ MT_Vector3 lv = lin_vel_local ? NodeGetWorldOrientation() * lin_vel : lin_vel;
+ MT_Vector3 av = ang_vel_local ? NodeGetWorldOrientation() * ang_vel : ang_vel;
+ m_pPhysicsController1->resolveCombinedVelocities(
+ lv.x(),lv.y(),lv.z(),av.x(),av.y(),av.z());
+ }
+}
+
+
+void KX_GameObject::SetObjectColor(const MT_Vector4& rgbavec)
+{
+ m_bUseObjectColor = true;
+ m_objectColor = rgbavec;
+}
+
+
+
+MT_Vector3 KX_GameObject::GetLinearVelocity()
+{
+ MT_Vector3 velocity(0.0,0.0,0.0);
+
+ if (m_pPhysicsController1)
+ {
+ velocity = m_pPhysicsController1->GetLinearVelocity();
+ }
+ return velocity;
+
+}
+
+
+// scenegraph node stuff
+
+void KX_GameObject::NodeSetLocalPosition(const MT_Point3& trans)
+{
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->setPosition(trans);
+ }
+
+ if (GetSGNode())
+ GetSGNode()->SetLocalPosition(trans);
+}
+
+
+
+void KX_GameObject::NodeSetLocalOrientation(const MT_Matrix3x3& rot)
+{
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->setOrientation(rot.getRotation());
+ }
+ if (GetSGNode())
+ GetSGNode()->SetLocalOrientation(rot);
+ else
+ {
+ int i;
+ i=0;
+ }
+}
+
+
+
+void KX_GameObject::NodeSetLocalScale(const MT_Vector3& scale)
+{
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->setScaling(scale);
+ }
+
+ if (GetSGNode())
+ GetSGNode()->SetLocalScale(scale);
+}
+
+
+
+void KX_GameObject::NodeSetRelativeScale(const MT_Vector3& scale)
+{
+ if (GetSGNode())
+ GetSGNode()->RelativeScale(scale);
+}
+
+
+
+void KX_GameObject::NodeUpdateGS(double time,bool bInitiator)
+{
+ if (GetSGNode())
+ GetSGNode()->UpdateWorldData(time);
+}
+
+
+
+const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const
+{
+ return GetSGNode()->GetWorldOrientation();
+}
+
+
+
+const MT_Vector3& KX_GameObject::NodeGetWorldScaling() const
+{
+ return GetSGNode()->GetWorldScaling();
+}
+
+
+
+const MT_Point3& KX_GameObject::NodeGetWorldPosition() const
+{
+ return GetSGNode()->GetWorldPosition();
+}
+
+/* Suspend/ resume: for the dynamic behaviour, there is a simple
+ * method. For the residual motion, there is not. I wonder what the
+ * correct solution is for Sumo. Remove from the motion-update tree?
+ *
+ * So far, only switch the physics and logic.
+ * */
+
+void KX_GameObject::Resume(void)
+{
+ if (m_suspended) {
+ SCA_IObject::Resume();
+ GetPhysicsController()->RestoreDynamics();
+
+ m_suspended = false;
+ }
+}
+
+void KX_GameObject::Suspend(void)
+{
+ if ((!m_ignore_activity_culling)
+ && (!m_suspended)) {
+ SCA_IObject::Suspend();
+ GetPhysicsController()->SuspendDynamics();
+ m_suspended = true;
+ }
+}
+
+
+
+
+/* ------- python stuff ---------------------------------------------------*/
+
+
+
+
+PyMethodDef KX_GameObject::Methods[] = {
+ {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS},
+ {"setPosition", (PyCFunction) KX_GameObject::sPySetPosition, METH_VARARGS},
+ {"getPosition", (PyCFunction) KX_GameObject::sPyGetPosition, METH_VARARGS},
+ {"getOrientation", (PyCFunction) KX_GameObject::sPyGetOrientation, METH_VARARGS},
+ {"setOrientation", (PyCFunction) KX_GameObject::sPySetOrientation, METH_VARARGS},
+ {"getLinearVelocity", (PyCFunction) KX_GameObject::sPyGetLinearVelocity, METH_VARARGS},
+ {"getVelocity", (PyCFunction) KX_GameObject::sPyGetVelocity, METH_VARARGS},
+ {"getMass", (PyCFunction) KX_GameObject::sPyGetMass, METH_VARARGS},
+ {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_VARARGS},
+ {"applyImpulse", (PyCFunction) KX_GameObject::sPyApplyImpulse, METH_VARARGS},
+ {"setCollisionMargin", (PyCFunction) KX_GameObject::sPySetCollisionMargin, METH_VARARGS},
+ {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics,METH_VARARGS},
+ {"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics,METH_VARARGS},
+ {"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody,METH_VARARGS},
+ {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_VARARGS},
+ {"getParent", (PyCFunction)KX_GameObject::sPyGetParent,METH_VARARGS},
+ {"getMesh", (PyCFunction)KX_GameObject::sPyGetMesh,METH_VARARGS},
+ {"getPhysicsId", (PyCFunction)KX_GameObject::sPyGetPhysicsId,METH_VARARGS},
+ KX_PYMETHODTABLE(KX_GameObject, getDistanceTo),
+ {NULL,NULL} //Sentinel
+};
+
+
+
+/*
+bool KX_GameObject::ConvertPythonVectorArgs(PyObject* args,
+ MT_Vector3& pos,
+ MT_Vector3& pos2)
+{
+ PyObject* pylist;
+ PyObject* pylist2;
+ bool error = (PyArg_ParseTuple(args,"OO",&pylist,&pylist2)) != 0;
+
+ pos = ConvertPythonPylist(pylist);
+ pos2 = ConvertPythonPylist(pylist2);
+
+ return error;
+}
+*/
+
+
+PyObject* KX_GameObject::sPySetPosition(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return ((KX_GameObject*) self)->PySetPosition(self, args, kwds);
+}
+
+
+
+PyObject* KX_GameObject::PyGetPosition(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyObjectFrom(NodeGetWorldPosition());
+}
+
+
+
+PyTypeObject KX_GameObject::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_GameObject",
+ sizeof(KX_GameObject),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+
+PyParentObject KX_GameObject::Parents[] = {
+ &KX_GameObject::Type,
+ &SCA_IObject::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+
+PyObject* KX_GameObject::_getattr(const STR_String& attr)
+{
+ if (m_pPhysicsController1)
+ {
+ if (attr == "mass")
+ return PyFloat_FromDouble(GetPhysicsController()->GetMass());
+ }
+
+ if (attr == "parent")
+ {
+ KX_GameObject* parent = GetParent();
+ if (parent)
+ {
+ parent->AddRef();
+ return parent;
+ }
+ Py_Return;
+ }
+
+ if (attr == "visible")
+ return PyInt_FromLong(m_bVisible);
+
+ if (attr == "position")
+ return PyObjectFrom(NodeGetWorldPosition());
+
+ if (attr == "orientation")
+ return PyObjectFrom(NodeGetWorldOrientation());
+
+ if (attr == "scaling")
+ return PyObjectFrom(NodeGetWorldScaling());
+
+ if (attr == "name")
+ return PyString_FromString(m_name.ReadPtr());
+
+ _getattr_up(SCA_IObject);
+}
+
+int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr method
+{
+ if (attr == "mass")
+ return 1;
+
+ if (attr == "parent")
+ return 1;
+
+ if (PyInt_Check(value))
+ {
+ int val = PyInt_AsLong(value);
+ if (attr == "visible")
+ {
+ SetVisible(val != 0);
+ return 0;
+ }
+ }
+
+ if (PySequence_Check(value))
+ {
+ if (attr == "orientation")
+ {
+ MT_Matrix3x3 rot;
+ if (PyObject_IsMT_Matrix(value, 3))
+ {
+ if (PyMatTo(value, rot))
+ {
+ NodeSetLocalOrientation(rot);
+ return 0;
+ }
+ return 1;
+ }
+
+ if (PySequence_Size(value) == 4)
+ {
+ MT_Quaternion qrot;
+ if (PyVecTo(value, qrot))
+ {
+ rot.setRotation(qrot);
+ NodeSetLocalOrientation(rot);
+ return 0;
+ }
+ return 1;
+ }
+
+ if (PySequence_Size(value) == 3)
+ {
+ MT_Vector3 erot;
+ if (PyVecTo(value, erot))
+ {
+ rot.setEuler(erot);
+ NodeSetLocalOrientation(rot);
+ return 0;
+ }
+ return 1;
+ }
+
+ return 1;
+ }
+
+ if (attr == "position")
+ {
+ MT_Point3 pos;
+ if (PyVecTo(value, pos))
+ {
+ NodeSetLocalPosition(pos);
+ return 0;
+ }
+ return 1;
+ }
+
+ if (attr == "scaling")
+ {
+ MT_Vector3 scale;
+ if (PyVecTo(value, scale))
+ {
+ NodeSetLocalScale(scale);
+ return 0;
+ }
+ return 1;
+ }
+ }
+
+ if (PyString_Check(value))
+ {
+ if (attr == "name")
+ {
+ m_name = PyString_AsString(value);
+ return 0;
+ }
+ }
+
+ return SCA_IObject::_setattr(attr, value);
+}
+
+
+PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ // only can get the velocity if we have a physics object connected to us...
+ return PyObjectFrom(GetLinearVelocity());
+}
+
+
+
+PyObject* KX_GameObject::PySetVisible(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int visible = 1;
+
+ if (PyArg_ParseTuple(args,"i",&visible))
+ {
+ MarkVisible(visible!=0);
+ m_bVisible = (visible!=0);
+ }
+ else
+ {
+ return NULL;
+ }
+ Py_Return;
+
+}
+
+
+
+PyObject* KX_GameObject::PyGetVelocity(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ // only can get the velocity if we have a physics object connected to us...
+ MT_Vector3 velocity(0.0,0.0,0.0);
+ MT_Point3 point(0.0,0.0,0.0);
+
+
+ PyObject* pypos = NULL;
+ if (PyArg_ParseTuple(args, "|O", &pypos))
+ {
+ if (pypos)
+ PyVecTo(pypos, point);
+ }
+
+ if (m_pPhysicsController1)
+ {
+ velocity = m_pPhysicsController1->GetVelocity(point);
+ }
+
+ return PyObjectFrom(velocity);
+}
+
+
+
+PyObject* KX_GameObject::PyGetMass(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject* pymass = NULL;
+
+ float mass = GetPhysicsController()->GetMass();
+ pymass = PyFloat_FromDouble(mass);
+
+ if (pymass)
+ return pymass;
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_GameObject::PyGetReactionForce(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ // only can get the velocity if we have a physics object connected to us...
+ return PyObjectFrom(GetPhysicsController()->getReactionForce());
+}
+
+
+
+PyObject* KX_GameObject::PyEnableRigidBody(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ GetPhysicsController()->setRigidBody(true);
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_GameObject::PyDisableRigidBody(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ GetPhysicsController()->setRigidBody(false);
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_GameObject::PyGetParent(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ KX_GameObject* parent = this->GetParent();
+ if (parent)
+ {
+ parent->AddRef();
+ return parent;
+ }
+ Py_Return;
+}
+
+
+
+PyObject* KX_GameObject::PyGetMesh(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int mesh = 0;
+
+ if (PyArg_ParseTuple(args, "|i", &mesh))
+ {
+ if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0)
+ {
+ KX_MeshProxy* meshproxy = new KX_MeshProxy(m_meshes[mesh]);
+ return meshproxy;
+ }
+ }
+ Py_Return;
+}
+
+
+
+
+
+PyObject* KX_GameObject::PySetCollisionMargin(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float collisionMargin;
+ if (PyArg_ParseTuple(args, "f", &collisionMargin))
+ {
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->setMargin(collisionMargin);
+ Py_Return;
+ }
+
+ }
+
+ return NULL;
+}
+
+
+
+PyObject* KX_GameObject::PyApplyImpulse(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject* pyattach;
+ PyObject* pyimpulse;
+ if (PyArg_ParseTuple(args, "OO", &pyattach, &pyimpulse))
+ {
+ MT_Point3 attach;
+ MT_Vector3 impulse;
+ if (m_pPhysicsController1)
+ {
+ if (PyVecTo(pyattach, attach) && PyVecTo(pyimpulse, impulse))
+ {
+ m_pPhysicsController1->applyImpulse(attach, impulse);
+ Py_Return;
+ }
+ }
+
+ }
+
+ return NULL;
+}
+
+
+
+PyObject* KX_GameObject::PySuspendDynamics(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ if (m_bSuspendDynamics)
+ {
+ Py_Return;
+ }
+
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->SuspendDynamics();
+ }
+ m_bSuspendDynamics = true;
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_GameObject::PyRestoreDynamics(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ if (!m_bSuspendDynamics)
+ {
+ Py_Return;
+ }
+
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->RestoreDynamics();
+ }
+ m_bSuspendDynamics = false;
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_GameObject::PyGetOrientation(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) //keywords
+{
+ return PyObjectFrom(NodeGetWorldOrientation());
+}
+
+
+
+PyObject* KX_GameObject::PySetOrientation(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject* pylist;
+
+ if (PyArg_ParseTuple(args,"O",&pylist))
+ {
+ MT_Matrix3x3 matrix;
+ if (PyObject_IsMT_Matrix(pylist, 3) && PyMatTo(pylist, matrix))
+ {
+ NodeSetLocalOrientation(matrix);
+ Py_Return;
+ }
+
+ MT_Quaternion quat;
+ if (PyVecTo(pylist, quat))
+ {
+ matrix.setRotation(quat);
+ NodeSetLocalOrientation(matrix);
+ Py_Return;
+ }
+ }
+ return NULL;
+}
+
+
+
+PyObject* KX_GameObject::PySetPosition(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ MT_Point3 pos;
+ if (PyVecArgTo(args, pos))
+ {
+ NodeSetLocalPosition(pos);
+ NodeUpdateGS(0.f,true);
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ KX_IPhysicsController* ctrl = GetPhysicsController();
+ uint_ptr physid=0;
+ if (ctrl)
+ {
+ physid= (uint_ptr)ctrl->GetUserData();
+ }
+ return PyInt_FromLong((long)physid);
+}
+
+KX_PYMETHODDEF_DOC(KX_GameObject, getDistanceTo,
+"getDistanceTo(other): get distance to another point/KX_GameObject")
+{
+ MT_Point3 b;
+ if (PyVecArgTo(args, b))
+ {
+ return PyFloat_FromDouble(NodeGetWorldPosition().distance(b));
+ }
+ PyErr_Clear();
+
+ PyObject *pyother;
+ if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &pyother))
+ {
+ KX_GameObject *other = static_cast<KX_GameObject*>(pyother);
+ return PyFloat_FromDouble(NodeGetWorldPosition().distance(other->NodeGetWorldPosition()));
+ }
+
+ return NULL;
+}
+
+/* ---------------------------------------------------------------------
+ * Some stuff taken from the header
+ * --------------------------------------------------------------------- */
+void KX_GameObject::Relink(GEN_Map<GEN_HashedPtr, void*> *map_parameter)
+{
+ /* intentionally empty ? */
+}
+
diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h
new file mode 100644
index 00000000000..db910a46a81
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_GameObject.h
@@ -0,0 +1,630 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 KX game object.
+ */
+
+#ifndef __KX_GAMEOBJECT
+#define __KX_GAMEOBJECT
+
+#ifdef WIN32
+// get rid of this stupid "warning 'this' used in initialiser list", generated by VC when including Solid/Sumo
+#pragma warning (disable : 4355)
+#endif
+
+
+#include "ListValue.h"
+#include "SCA_IObject.h"
+#include "SG_Node.h"
+#include "MT_Transform.h"
+#include "MT_CmMatrix4x4.h"
+#include "GEN_Map.h"
+#include "GEN_HashedPtr.h"
+
+#define KX_FIXED_FRAME_PER_SEC 25.0f
+#define KX_FIXED_SEC_PER_FRAME (1.0f / KX_FIXED_FRAME_PER_SEC)
+#define KX_OB_DYNAMIC 1
+
+
+//Forward declarations.
+struct KX_ClientObjectInfo;
+class RAS_MeshObject;
+class KX_IPhysicsController;
+
+
+/**
+ * KX_GameObject is the main class for dynamic objects.
+ */
+class KX_GameObject : public SCA_IObject
+{
+ Py_Header;
+protected:
+
+ bool m_bDyna;
+ KX_ClientObjectInfo* m_pClient_info;
+ STR_String m_name;
+ STR_String m_text;
+ std::vector<RAS_MeshObject*> m_meshes;
+
+ bool m_bSuspendDynamics;
+ bool m_bUseObjectColor;
+ MT_Vector4 m_objectColor;
+
+ // Is this object set to be visible? Only useful for the
+ // visibility subsystem right now.
+ bool m_bVisible;
+
+ KX_IPhysicsController* m_pPhysicsController1;
+ SG_Node* m_pSGNode;
+
+ MT_CmMatrix4x4 m_OpenGL_4x4Matrix;
+
+public:
+ bool m_isDeformable;
+
+ virtual void /* This function should be virtual - derived classed override it */
+ Relink(
+ GEN_Map<GEN_HashedPtr, void*> *map
+ );
+
+ /**
+ * Compute an OpenGl compatable 4x4 matrix. Has the
+ * side effect of storing the result internally. The
+ * memory for the matrix remains the property of this class.
+ */
+ double*
+ GetOpenGLMatrix(
+ );
+
+ /**
+ * Return a pointer to a MT_CmMatrix4x4 storing the
+ * opengl transformation for this object. This is updated
+ * by a call to GetOpenGLMatrix(). This class owns the
+ * memory for the returned matrix.
+ */
+
+ MT_CmMatrix4x4*
+ GetOpenGLMatrixPtr(
+ ) {
+ return &m_OpenGL_4x4Matrix;
+ };
+
+ /**
+ * Get a pointer to the game object that is the parent of
+ * this object. Or NULL if there is no parent. The returned
+ * object is part of a reference counting scheme. Calling
+ * this function ups the reference count on the returned
+ * object. It is the responsibility of the caller to decrement
+ * the reference count when you have finished with it.
+ */
+ KX_GameObject*
+ GetParent(
+ );
+
+
+ /**
+ * Construct a game object. This class also inherits the
+ * default constructors - use those with care!
+ */
+
+ KX_GameObject(
+ void* sgReplicationInfo,
+ SG_Callbacks callbacks,
+ PyTypeObject* T=&Type
+ );
+
+ virtual
+ ~KX_GameObject(
+ );
+
+ CValue*
+ AddRef() {
+ /* temporarily to find memleaks */ return CValue::AddRef();
+ }
+
+ /**
+ * @section Stuff which is here due to poor design.
+ * Inherited from CValue and needs an implementation.
+ * Do not expect these functions do to anything sensible.
+ */
+
+ /**
+ * Inherited from CValue -- does nothing!
+ */
+ CValue*
+ Calc(
+ VALUE_OPERATOR op,
+ CValue *val
+ );
+
+ /**
+ * Inherited from CValue -- does nothing!
+ */
+ CValue*
+ CalcFinal(
+ VALUE_DATA_TYPE dtype,
+ VALUE_OPERATOR op,
+ CValue *val
+ );
+
+ /**
+ * Inherited from CValue -- does nothing!
+ */
+ const
+ STR_String &
+ GetText(
+ );
+
+ /**
+ * Inherited from CValue -- does nothing!
+ */
+ float
+ GetNumber(
+ );
+
+ /**
+ * @section Inherited from CValue. These are the useful
+ * part of the CValue interface that this class implements.
+ */
+
+ /**
+ * Inherited from CValue -- returns the name of this object.
+ */
+ STR_String
+ GetName(
+ );
+
+ /**
+ * Inherited from CValue -- set the name of this object.
+ */
+ void
+ SetName(
+ STR_String name
+ );
+
+ /**
+ * Inherited from CValue -- does nothing.
+ */
+ void
+ ReplicaSetName(
+ STR_String name
+ );
+
+ /**
+ * Inherited from CValue -- return a new copy of this
+ * instance allocated on the heap. Ownership of the new
+ * object belongs with the caller.
+ */
+ virtual CValue*
+ GetReplica(
+ );
+
+ /**
+ * Inherited from CValue -- Makes sure any internal
+ * data owned by this class is deep copied. Called internally
+ */
+ virtual void
+ ProcessReplica(
+ KX_GameObject* replica
+ );
+
+ /**
+ * Return the linear velocity of the game object.
+ */
+ MT_Vector3
+ GetLinearVelocity(
+ );
+
+ /**
+ * Quick'n'dirty obcolor ipo stuff
+ */
+
+ void
+ SetObjectColor(
+ const MT_Vector4& rgbavec
+ );
+
+
+ void
+ ResolveCombinedVelocities(
+ const MT_Vector3 & lin_vel,
+ const MT_Vector3 & ang_vel,
+ bool lin_vel_local,
+ bool ang_vel_local
+ );
+
+
+ /**
+ * @return a pointer to the physics controller owned by this class.
+ */
+
+ KX_IPhysicsController* GetPhysicsController() ;
+
+ void SetPhysicsController(KX_IPhysicsController* physicscontroller,bool isDynamic)
+ {
+ m_bDyna = isDynamic;
+ m_pPhysicsController1 = physicscontroller;
+ }
+
+
+ /**
+ * @section Coordinate system manipulation functions
+ */
+
+ void NodeSetLocalPosition(const MT_Point3& trans );
+
+ void NodeSetLocalOrientation(const MT_Matrix3x3& rot );
+
+ void NodeSetLocalScale( const MT_Vector3& scale );
+
+ void NodeSetRelativeScale( const MT_Vector3& scale );
+
+ void
+ NodeUpdateGS(
+ double time,
+ bool bInitiator
+ );
+
+ const
+ MT_Matrix3x3&
+ NodeGetWorldOrientation(
+ ) const;
+
+ const
+ MT_Vector3&
+ NodeGetWorldScaling(
+ ) const;
+
+ const
+ MT_Point3&
+ NodeGetWorldPosition(
+ ) const;
+
+
+ /**
+ * @section scene graph node accessor functions.
+ */
+
+ SG_Node* GetSGNode( )
+ {
+ return m_pSGNode;
+ }
+
+ const SG_Node* GetSGNode( ) const
+ {
+ return m_pSGNode;
+ }
+
+ /**
+ * Set the Scene graph node for this game object.
+ * warning - it is your responsibility to make sure
+ * all controllers look at this new node. You must
+ * also take care of the memory associated with the
+ * old node. This class takes ownership of the new
+ * node.
+ */
+ void SetSGNode(SG_Node* node )
+ {
+ m_pSGNode = node;
+ }
+
+ //Is it a dynamic/physics object ?
+ bool IsDynamic() const
+ {
+ return m_bDyna;
+ }
+
+
+ /**
+ * @section Physics accessors for this node.
+ *
+ * All these calls get passed directly to the physics controller
+ * owned by this object.
+ * This is real interface bloat. Why not just use the physics controller
+ * directly? I think this is because the python interface is in the wrong
+ * place.
+ */
+
+ void
+ ApplyForce(
+ const MT_Vector3& force, bool local
+ );
+
+ void
+ ApplyTorque(
+ const MT_Vector3& torque,
+ bool local
+ );
+
+ void
+ ApplyRotation(
+ const MT_Vector3& drot,
+ bool local
+ );
+
+ void
+ ApplyMovement(
+ const MT_Vector3& dloc,
+ bool local
+ );
+
+ void
+ addLinearVelocity(
+ const MT_Vector3& lin_vel,
+ bool local
+ );
+
+ void
+ setLinearVelocity(
+ const MT_Vector3& lin_vel,
+ bool local
+ );
+
+ void
+ setAngularVelocity(
+ const MT_Vector3& ang_vel,
+ bool local
+ );
+
+ /**
+ * Update the physics object transform based upon the current SG_Node
+ * position.
+ */
+ void
+ UpdateTransform(
+ );
+
+ static void UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene);
+
+ /**
+ * Only update the transform if it's a non-dynamic object
+ */
+ void
+ UpdateNonDynas(
+ );
+
+ /**
+ * Odd function to update an ipo. ???
+ */
+ void
+ UpdateIPO(
+ float curframetime,
+ bool recurse,
+ bool ipo_as_force,
+ bool force_ipo_local
+ );
+ /**
+ * Updates Material Ipo data
+ */
+ void
+ UpdateMaterialData(
+ MT_Vector4 rgba,
+ MT_Vector3 specrgb,
+ MT_Scalar hard,
+ MT_Scalar spec,
+ MT_Scalar ref,
+ MT_Scalar emit,
+ MT_Scalar alpha
+ );
+
+ /**
+ * @section Mesh accessor functions.
+ */
+
+ /**
+ * Run through the meshes associated with this
+ * object and bucketize them. See RAS_Mesh for
+ * more details on this function. Interesting to
+ * note that polygon bucketizing seems to happen on a per
+ * object basis. Which may explain why there is such
+ * a big performance gain when all static objects
+ * are joined into 1.
+ */
+ void
+ Bucketize(
+ );
+
+ /**
+ * Clear the meshes associated with this class
+ * and remove from the bucketing system.
+ * Don't think this actually deletes any of the meshes.
+ */
+ void
+ RemoveMeshes(
+ );
+
+ /**
+ * Add a mesh to the set of meshes associated with this
+ * node. Meshes added in this way are not deleted by this class.
+ * Make sure you call RemoveMeshes() before deleting the
+ * mesh though,
+ */
+ void
+ AddMesh(
+ RAS_MeshObject* mesh
+ ){
+ m_meshes.push_back(mesh);
+ }
+
+ /**
+ * Pick out a mesh associated with the integer 'num'.
+ */
+ RAS_MeshObject*
+ GetMesh(
+ int num
+ ) const {
+ return m_meshes[num];
+ }
+
+ /**
+ * Return the number of meshes currently associated with this
+ * game object.
+ */
+ int
+ GetMeshCount(
+ ) const {
+ return m_meshes.size();
+ }
+
+ /**
+ * Set the debug color of the meshes associated with this
+ * class. Does this still work?
+ */
+ void
+ SetDebugColor(
+ unsigned int bgra
+ );
+
+ /**
+ * Reset the debug color of meshes associated with this class.
+ */
+ void
+ ResetDebugColor(
+ );
+
+ /**
+ * Set the visibility of the meshes associated with this
+ * object.
+ */
+ void
+ MarkVisible(
+ bool visible
+ );
+
+ /**
+ * Set the visibility according to the visibility flag.
+ */
+ void
+ MarkVisible(
+ void
+ );
+
+ /**
+ * Was this object marked visible? (only for the ewxplicit
+ * visibility system).
+ */
+ bool
+ GetVisible(
+ void
+ );
+
+ /**
+ * Set visibility flag of this object
+ */
+ void
+ SetVisible(
+ bool b
+ );
+
+
+ /**
+ * @section Logic bubbling methods.
+ */
+
+ /**
+ * Stop making progress
+ */
+ void Suspend(void);
+
+ /**
+ * Resume making progress
+ */
+ void Resume(void);
+
+ KX_ClientObjectInfo* getClientInfo() { return m_pClient_info; }
+ /**
+ * @section Python interface functions.
+ */
+
+ virtual
+ PyObject*
+ _getattr(
+ const STR_String& attr
+ );
+
+ virtual
+ int
+ _setattr(
+ const STR_String& attr,
+ PyObject *value
+ ); // _setattr method
+
+ PyObject*
+ PySetPosition(
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds
+ );
+
+ static
+ PyObject*
+ sPySetPosition(
+ PyObject* self,
+ PyObject* args,
+ PyObject* kwds
+ );
+
+ KX_PYMETHOD(KX_GameObject,GetPosition);
+ KX_PYMETHOD(KX_GameObject,GetLinearVelocity);
+ KX_PYMETHOD(KX_GameObject,GetVelocity);
+ KX_PYMETHOD(KX_GameObject,GetMass);
+ KX_PYMETHOD(KX_GameObject,GetReactionForce);
+ KX_PYMETHOD(KX_GameObject,GetOrientation);
+ KX_PYMETHOD(KX_GameObject,SetOrientation);
+ KX_PYMETHOD(KX_GameObject,SetVisible);
+ KX_PYMETHOD(KX_GameObject,SuspendDynamics);
+ KX_PYMETHOD(KX_GameObject,RestoreDynamics);
+ KX_PYMETHOD(KX_GameObject,EnableRigidBody);
+ KX_PYMETHOD(KX_GameObject,DisableRigidBody);
+ KX_PYMETHOD(KX_GameObject,ApplyImpulse);
+ KX_PYMETHOD(KX_GameObject,SetCollisionMargin);
+ KX_PYMETHOD(KX_GameObject,GetMesh);
+ KX_PYMETHOD(KX_GameObject,GetParent);
+ KX_PYMETHOD(KX_GameObject,GetPhysicsId);
+ KX_PYMETHOD_DOC(KX_GameObject,getDistanceTo);
+private :
+
+ /**
+ * Random internal function to convert python function arguments
+ * to 2 vectors.
+ * @return true if conversion was possible.
+ */
+
+ bool
+ ConvertPythonVectorArgs(
+ PyObject* args,
+ MT_Vector3& pos,
+ MT_Vector3& pos2
+ );
+
+};
+
+#endif //__KX_GAMEOBJECT
+
diff --git a/source/gameengine/Ketsji/KX_IInterpolator.h b/source/gameengine/Ketsji/KX_IInterpolator.h
new file mode 100644
index 00000000000..6a59f537c8d
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_IInterpolator.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 KX_IINTERPOLATOR_H
+#define KX_IINTERPOLATOR_H
+
+#include <vector>
+
+class KX_IInterpolator {
+public:
+ virtual ~KX_IInterpolator() {}
+
+ virtual void Execute(float currentTime) const = 0;
+};
+
+typedef std::vector<KX_IInterpolator *> T_InterpolatorList;
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_IPOTransform.h b/source/gameengine/Ketsji/KX_IPOTransform.h
new file mode 100644
index 00000000000..45c6d0d9459
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_IPOTransform.h
@@ -0,0 +1,89 @@
+/**
+ * An abstract object you can move around in a 3d world, and has some logic
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 KX_IPOTRANSFORM_H
+#define KX_IPOTRANSFORM_H
+
+#include "MT_Transform.h"
+
+class KX_IPOTransform {
+public:
+ KX_IPOTransform() :
+ m_position(0.0, 0.0, 0.0),
+ m_eulerAngles(0.0, 0.0, 0.0),
+ m_scaling(1.0, 1.0, 1.0),
+ m_deltaPosition(0.0, 0.0, 0.0),
+ m_deltaEulerAngles(0.0, 0.0, 0.0),
+ m_deltaScaling(0.0, 0.0, 0.0)
+ {}
+
+ MT_Transform GetTransform() const {
+ return MT_Transform(m_position + m_deltaPosition,
+ MT_Matrix3x3(m_eulerAngles + m_deltaEulerAngles,
+ m_scaling + m_deltaScaling));
+ }
+
+ MT_Point3& GetPosition() { return m_position; }
+ MT_Vector3& GetEulerAngles() { return m_eulerAngles; }
+ MT_Vector3& GetScaling() { return m_scaling; }
+
+ const MT_Point3& GetPosition() const { return m_position; }
+ const MT_Vector3& GetEulerAngles() const { return m_eulerAngles; }
+ const MT_Vector3& GetScaling() const { return m_scaling; }
+
+ MT_Vector3& GetDeltaPosition() { return m_deltaPosition; }
+ MT_Vector3& GetDeltaEulerAngles() { return m_deltaEulerAngles; }
+ MT_Vector3& GetDeltaScaling() { return m_deltaScaling; }
+
+ void SetPosition(const MT_Point3& pos) { m_position = pos; }
+ void SetEulerAngles(const MT_Vector3& eul) { m_eulerAngles = eul; }
+ void SetScaling(const MT_Vector3& scaling) { m_scaling = scaling; }
+
+ void ClearDeltaStuff() {
+ m_deltaPosition.setValue(0.0, 0.0, 0.0);
+ m_deltaEulerAngles.setValue(0.0, 0.0, 0.0);
+ m_deltaScaling.setValue(0.0, 0.0, 0.0);
+ }
+
+protected:
+ MT_Point3 m_position;
+ MT_Vector3 m_eulerAngles;
+ MT_Vector3 m_scaling;
+ MT_Vector3 m_deltaPosition;
+ MT_Vector3 m_deltaEulerAngles;
+ MT_Vector3 m_deltaScaling;
+};
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.cpp b/source/gameengine/Ketsji/KX_IPO_SGController.cpp
new file mode 100644
index 00000000000..920a65be0fb
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_IPO_SGController.cpp
@@ -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 *****
+ * Scenegraph controller for ipos.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(_WIN64)
+typedef unsigned __int64 uint_ptr;
+#else
+typedef unsigned long uint_ptr;
+#endif
+
+#ifdef WIN32
+// This warning tells us about truncation of __long__ stl-generated names.
+// It can occasionally cause DevStudio to have internal compiler warnings.
+#pragma warning( disable : 4786 )
+#endif
+
+#include "KX_IPO_SGController.h"
+#include "KX_ScalarInterpolator.h"
+#include "KX_GameObject.h"
+#include "KX_IPhysicsController.h"
+
+// All objects should start on frame 1! Will we ever need an object to
+// start on another frame, the 1.0 should change.
+KX_IpoSGController::KX_IpoSGController()
+: m_modify_position(false),
+ m_modify_orientation(false),
+ m_modify_scaling(false),
+ m_ipo_as_force(false),
+ m_force_ipo_acts_local(false),
+ m_modified(true),
+ m_ipotime(1.0)
+{
+ m_game_object = NULL;
+
+}
+
+
+void KX_IpoSGController::SetOption(
+ int option,
+ int value)
+{
+ switch (option) {
+ case SG_CONTR_IPO_IPO_AS_FORCE:
+ m_ipo_as_force = (value != 0);
+ m_modified = true;
+ break;
+ case SG_CONTR_IPO_FORCES_ACT_LOCAL:
+ m_force_ipo_acts_local = (value != 0);
+ m_modified = true;
+ break;
+ default:
+ ; /* just ignore the rest */
+ }
+}
+
+ void
+KX_IpoSGController::UpdateSumoReference(
+ )
+{
+ if (m_game_object) {
+
+ }
+}
+
+ void
+KX_IpoSGController::SetGameObject(
+ KX_GameObject* go
+ )
+{
+ m_game_object = go;
+}
+
+
+
+bool KX_IpoSGController::Update(double currentTime)
+{
+ if (m_modified)
+ {
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ (*i)->Execute(m_ipotime);//currentTime);
+ }
+
+ SG_Spatial* ob = (SG_Spatial*)m_pObject;
+
+ if (m_modify_position) {
+ if (m_ipo_as_force) {
+
+ if (m_game_object && ob) {
+ m_game_object->GetPhysicsController()->ApplyForce(m_force_ipo_acts_local ?
+ ob->GetWorldOrientation() * m_ipo_xform.GetPosition() :
+ m_ipo_xform.GetPosition(), false);
+ }
+
+ } else {
+ ob->SetLocalPosition(m_ipo_xform.GetPosition());
+ }
+ }
+ if (m_modify_orientation) {
+ if (m_ipo_as_force) {
+
+ if (m_game_object && ob) {
+ m_game_object->ApplyTorque(m_force_ipo_acts_local ?
+ ob->GetWorldOrientation() * m_ipo_xform.GetEulerAngles() :
+ m_ipo_xform.GetEulerAngles(), false);
+ }
+
+ } else {
+ ob->SetLocalOrientation(MT_Matrix3x3(m_ipo_xform.GetEulerAngles()));
+ }
+ }
+ if (m_modify_scaling)
+ ob->SetLocalScale(m_ipo_xform.GetScaling());
+
+ m_modified=false;
+ }
+ return false;
+}
+
+
+void KX_IpoSGController::AddInterpolator(KX_IInterpolator* interp)
+{
+ this->m_interpolators.push_back(interp);
+}
+
+SG_Controller* KX_IpoSGController::GetReplica(class SG_Node* destnode)
+{
+ KX_IpoSGController* iporeplica = new KX_IpoSGController(*this);
+ // clear object that ipo acts on in the replica.
+ iporeplica->ClearObject();
+
+ // dirty hack, ask Gino for a better solution in the ipo implementation
+ // hacken en zagen, in what we call datahiding, not written for replication :(
+
+ T_InterpolatorList oldlist = m_interpolators;
+ iporeplica->m_interpolators.clear();
+
+ T_InterpolatorList::iterator i;
+ for (i = oldlist.begin(); !(i == oldlist.end()); ++i) {
+ KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i));
+ iporeplica->AddInterpolator(copyipo);
+
+ MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget();
+ uint_ptr orgbase = (uint_ptr)&m_ipo_xform;
+ uint_ptr orgloc = (uint_ptr)scaal;
+ uint_ptr offset = orgloc-orgbase;
+ uint_ptr newaddrbase = (uint_ptr)&iporeplica->m_ipo_xform;
+ newaddrbase += offset;
+ MT_Scalar* blaptr = (MT_Scalar*) newaddrbase;
+ copyipo->SetNewTarget((MT_Scalar*)blaptr);
+ }
+
+ return iporeplica;
+}
+
+KX_IpoSGController::~KX_IpoSGController()
+{
+
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ delete (*i);
+ }
+
+}
diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.h b/source/gameengine/Ketsji/KX_IPO_SGController.h
new file mode 100644
index 00000000000..3b20f47f5fc
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_IPO_SGController.h
@@ -0,0 +1,107 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __IPO_SGCONTROLLER_H
+#define __IPO_SGCONTROLLER_H
+
+#include "SG_Controller.h"
+#include "SG_Spatial.h"
+
+#include "KX_IPOTransform.h"
+#include "KX_IInterpolator.h"
+
+class KX_IpoSGController : public SG_Controller
+{
+ KX_IPOTransform m_ipo_xform;
+ T_InterpolatorList m_interpolators;
+ /* Why not bools? */
+ short m_modify_position : 1;
+ short m_modify_orientation : 1;
+ short m_modify_scaling : 1;
+
+ /** Interpret the ipo as a force rather than a displacement? */
+ bool m_ipo_as_force;
+
+ /** Ipo-as-force acts in local rather than in global coordinates? */
+ bool m_force_ipo_acts_local;
+
+ /** Were settings altered since the last update? */
+ bool m_modified;
+
+ /** Local time of this ipo.*/
+ double m_ipotime;
+
+ /** A reference to the original game object. */
+ class KX_GameObject* m_game_object;
+
+public:
+ KX_IpoSGController();
+
+ virtual ~KX_IpoSGController();
+
+ virtual SG_Controller* GetReplica(class SG_Node* destnode);
+
+ void
+ SetOption(
+ int option,
+ int value
+ );
+
+ /** Set sumo data. */
+ void UpdateSumoReference();
+ /** Set reference to the corresponding game object. */
+ void SetGameObject(class KX_GameObject*);
+
+ void SetModifyPosition(bool modifypos) {
+ m_modify_position=modifypos;
+ }
+ void SetModifyOrientation(bool modifyorient) {
+ m_modify_orientation=modifyorient;
+ }
+ void SetModifyScaling(bool modifyscale) {
+ m_modify_scaling=modifyscale;
+ }
+
+ KX_IPOTransform& GetIPOTransform()
+ {
+ return m_ipo_xform;
+ }
+ void AddInterpolator(KX_IInterpolator* interp);
+ virtual bool Update(double time);
+ virtual void SetSimulatedTime(double time)
+ {
+ m_ipotime = time;
+ m_modified = true;
+ }
+};
+
+#endif //__IPO_SGCONTROLLER_H
+
diff --git a/source/gameengine/Ketsji/KX_IPhysicsController.cpp b/source/gameengine/Ketsji/KX_IPhysicsController.cpp
new file mode 100644
index 00000000000..c2328e45435
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_IPhysicsController.cpp
@@ -0,0 +1,53 @@
+/**
+ * @file KX_IPhysicsController.cpp
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_IPhysicsController.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "PHY_DynamicTypes.h"
+
+KX_IPhysicsController::KX_IPhysicsController(bool dyna,void* userdata)
+
+: m_bDyna(dyna),
+ m_suspendDynamics(false),
+ m_userdata(userdata)
+{
+}
+
+KX_IPhysicsController::~KX_IPhysicsController()
+{
+}
+
+
diff --git a/source/gameengine/Ketsji/KX_IPhysicsController.h b/source/gameengine/Ketsji/KX_IPhysicsController.h
new file mode 100644
index 00000000000..faf32bccbcd
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_IPhysicsController.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 __KX_IPHYSICSCONTROLLER_H
+#define __KX_IPHYSICSCONTROLLER_H
+
+#include "SG_Controller.h"
+#include "MT_Vector3.h"
+#include "MT_Point3.h"
+#include "MT_Matrix3x3.h"
+
+struct KX_ClientObjectInfo;
+
+/**
+ Physics Controller, a special kind of Scene Graph Transformation Controller.
+ It get's callbacks from Physics in case a transformation change took place.
+ Each time the scene graph get's updated, the controller get's a chance
+ in the 'Update' method to reflect changed.
+*/
+
+class KX_IPhysicsController : public SG_Controller
+
+{
+protected:
+ bool m_bDyna;
+ bool m_suspendDynamics;
+ void* m_userdata;
+public:
+ KX_IPhysicsController(bool dyna,void* userdata);
+ virtual ~KX_IPhysicsController();
+
+
+ virtual void applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse)=0;
+ virtual void SetObject (SG_IObject* object)=0;
+ virtual void setMargin (float collisionMargin)=0;
+
+ virtual void RelativeTranslate(const MT_Vector3& dloc,bool local)=0;
+ virtual void RelativeRotate(const MT_Matrix3x3& drot,bool local)=0;
+ virtual void ApplyTorque(const MT_Vector3& torque,bool local)=0;
+ virtual void ApplyForce(const MT_Vector3& force,bool local)=0;
+ virtual MT_Vector3 GetLinearVelocity()=0;
+ virtual MT_Vector3 GetVelocity(const MT_Point3& pos)=0;
+ virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local)=0;
+ virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local)=0;
+ virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) = 0;
+
+ virtual void getOrientation(MT_Quaternion& orn)=0;
+ virtual void setOrientation(const MT_Quaternion& orn)=0;
+ virtual void setPosition(const MT_Point3& pos)=0;
+ virtual void setScaling(const MT_Vector3& scaling)=0;
+ virtual MT_Scalar GetMass()=0;
+ virtual MT_Vector3 getReactionForce()=0;
+ virtual void setRigidBody(bool rigid)=0;
+
+ virtual void SuspendDynamics()=0;
+ virtual void RestoreDynamics()=0;
+
+ virtual SG_Controller* GetReplica(class SG_Node* destnode)=0;
+
+ void SetDyna(bool isDynamic) {
+ m_bDyna = isDynamic;
+ }
+
+
+ virtual void SetSumoTransform(bool nondynaonly)=0;
+ // todo: remove next line !
+ virtual void SetSimulatedTime(double time)=0;
+
+ // call from scene graph to update
+ virtual bool Update(double time)=0;
+ void* GetUserData() { return m_userdata;}
+};
+
+#endif //__KX_IPHYSICSCONTROLLER_H
+
diff --git a/source/gameengine/Ketsji/KX_IScalarInterpolator.h b/source/gameengine/Ketsji/KX_IScalarInterpolator.h
new file mode 100644
index 00000000000..f5d23d3e4e0
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_IScalarInterpolator.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef KX_ISCALARINTERPOLATOR_H
+#define KX_ISCALARINTERPOLATOR_H
+
+class KX_IScalarInterpolator {
+public:
+ virtual ~KX_IScalarInterpolator() {}
+
+ virtual float GetValue(float currentTime) const = 0;
+};
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_ISceneConverter.h b/source/gameengine/Ketsji/KX_ISceneConverter.h
new file mode 100644
index 00000000000..2e4250dfe1e
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ISceneConverter.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef __KX_ISCENECONVERTER_H
+#define __KX_ISCENECONVERTER_H
+
+#include "STR_String.h"
+#include "KX_Python.h"
+
+class KX_ISceneConverter
+{
+
+public:
+ KX_ISceneConverter() :addInitFromFrame(false) {}//this addInitFromFrame is a back hack, todo remove
+ virtual ~KX_ISceneConverter () {};
+
+ /*
+ scenename: name of the scene to be converted,
+ if the scenename is empty, convert the 'default' scene (whatever this means)
+ destinationscene: pass an empty scene, everything goes into this
+ dictobj: python dictionary (for pythoncontrollers)
+ */
+ virtual void ConvertScene(const STR_String& scenename,
+ class KX_Scene* destinationscene,
+ PyObject* dictobj,
+ class SCA_IInputDevice* keyinputdev,
+ class RAS_IRenderTools* rendertools,
+ class RAS_ICanvas* canvas)=0;
+
+ virtual void SetAlwaysUseExpandFraming(bool to_what) = 0;
+
+ virtual void SetNewFileName(const STR_String& filename) = 0;
+ virtual bool TryAndLoadNewFile() = 0;
+ bool addInitFromFrame;//rcruiz
+
+ virtual void ResetPhysicsObjectsAnimationIpo(bool clearIpo) = 0;
+
+
+ ///this generates ipo curves for position, rotation, allowing to use game physics in animation
+ virtual void WritePhysicsObjectToAnimationIpo(int frameNumber) = 0;
+ virtual void TestHandlesPhysicsObjectToAnimationIpo() = 0;
+
+ ///this is for reseting the position,rotation and scale of the gameobjet that is not dynamic
+ virtual void resetNoneDynamicObjectToIpo()=0;
+
+ // use blender materials
+ virtual void SetMaterials(bool val) =0;
+ virtual bool GetMaterials()=0;
+
+};
+
+#endif //__KX_ISCENECONVERTER_H
+
diff --git a/source/gameengine/Ketsji/KX_ISystem.h b/source/gameengine/Ketsji/KX_ISystem.h
new file mode 100644
index 00000000000..bf404bd3af7
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ISystem.h
@@ -0,0 +1,56 @@
+/**
+* Abstract 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 *****
+*/
+
+#ifndef __KX_ISYSTEM
+#define __KX_ISYSTEM
+
+#include <vector>
+using namespace std;
+
+#include "STR_String.h"
+
+/**
+ * System Abstraction, needed only for getting some timing stuff from the host.
+ */
+class KX_ISystem
+{
+public:
+ KX_ISystem() {};
+ virtual ~KX_ISystem() {};
+
+ virtual double GetTimeInSeconds()=0;
+};
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_IpoActuator.cpp b/source/gameengine/Ketsji/KX_IpoActuator.cpp
new file mode 100644
index 00000000000..e7f1dea7bbf
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_IpoActuator.cpp
@@ -0,0 +1,720 @@
+/**
+ * Do Ipo 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 *****
+ */
+
+#if defined (__sgi)
+#include <math.h>
+#else
+#include <cmath>
+#endif
+
+#include "KX_IpoActuator.h"
+#include "KX_GameObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "KX_KetsjiEngine.h"
+
+/* ------------------------------------------------------------------------- */
+/* Type strings */
+/* ------------------------------------------------------------------------- */
+
+STR_String KX_IpoActuator::S_KX_ACT_IPO_PLAY_STRING = "Play";
+STR_String KX_IpoActuator::S_KX_ACT_IPO_PINGPONG_STRING = "PingPong";
+STR_String KX_IpoActuator::S_KX_ACT_IPO_FLIPPER_STRING = "Flipper";
+STR_String KX_IpoActuator::S_KX_ACT_IPO_LOOPSTOP_STRING = "LoopStop";
+STR_String KX_IpoActuator::S_KX_ACT_IPO_LOOPEND_STRING = "LoopEnd";
+STR_String KX_IpoActuator::S_KX_ACT_IPO_KEY2KEY_STRING = "Key2key";
+STR_String KX_IpoActuator::S_KX_ACT_IPO_FROM_PROP_STRING = "FromProp";
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+/** Another poltergeist? This seems to be a very transient class... */
+class CIpoAction : public CAction
+{
+ float m_curtime;
+ bool m_recurse;
+ KX_GameObject* m_gameobj;
+ bool m_ipo_as_force;
+ bool m_force_ipo_local;
+
+public:
+ CIpoAction(KX_GameObject* gameobj,
+ float curtime,
+ bool recurse,
+ bool ipo_as_force,
+ bool force_ipo_local) :
+ m_curtime(curtime) ,
+ m_recurse(recurse),
+ m_gameobj(gameobj),
+ m_ipo_as_force(ipo_as_force),
+ m_force_ipo_local(force_ipo_local)
+ {
+ /* intentionally empty */
+ };
+
+ virtual void Execute() const
+ {
+ m_gameobj->UpdateIPO(
+ m_curtime,
+ m_recurse,
+ m_ipo_as_force,
+ m_force_ipo_local);
+ };
+
+};
+
+KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj,
+ const STR_String& propname,
+ float starttime,
+ float endtime,
+ bool recurse,
+ int acttype,
+ bool ipo_as_force,
+ bool force_ipo_local,
+ PyTypeObject* T)
+ : SCA_IActuator(gameobj,T),
+ m_bNegativeEvent(false),
+ m_startframe (starttime),
+ m_endframe(endtime),
+ m_recurse(recurse),
+ m_localtime(starttime),
+ m_direction(1),
+ m_propname(propname),
+ m_ipo_as_force(ipo_as_force),
+ m_force_ipo_local(force_ipo_local),
+ m_type((IpoActType)acttype)
+{
+ m_starttime = -2.0*fabs(m_endframe - m_startframe) - 1.0;
+ m_bIpoPlaying = false;
+}
+
+void KX_IpoActuator::SetStart(float starttime)
+{
+ m_startframe=starttime;
+}
+
+void KX_IpoActuator::SetEnd(float endtime)
+{
+ m_endframe=endtime;
+}
+
+bool KX_IpoActuator::ClampLocalTime()
+{
+ if (m_startframe < m_endframe)
+ {
+ if (m_localtime < m_startframe)
+ {
+ m_localtime = m_startframe;
+ return true;
+ }
+ else if (m_localtime > m_endframe)
+ {
+ m_localtime = m_endframe;
+ return true;
+ }
+ } else {
+ if (m_localtime > m_startframe)
+ {
+ m_localtime = m_startframe;
+ return true;
+ }
+ else if (m_localtime < m_endframe)
+ {
+ m_localtime = m_endframe;
+ return true;
+ }
+ }
+ return false;
+}
+
+void KX_IpoActuator::SetStartTime(float curtime)
+{
+ float direction = m_startframe < m_endframe ? 1.0 : -1.0;
+
+ curtime = curtime - KX_KetsjiEngine::GetSuspendedDelta();
+ if (m_direction > 0)
+ m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_FIXED_FRAME_PER_SEC;
+ else
+ m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_FIXED_FRAME_PER_SEC;
+}
+
+void KX_IpoActuator::SetLocalTime(float curtime)
+{
+ float delta_time = ((curtime - m_starttime) - KX_KetsjiEngine::GetSuspendedDelta())*KX_FIXED_FRAME_PER_SEC;
+
+ // negative delta_time is caused by floating point inaccuracy
+ // perhaps the inaccuracy could be reduced a bit
+ if ((m_localtime==m_startframe || m_localtime==m_endframe) && delta_time<0.0)
+ {
+ delta_time = 0.0;
+ }
+
+ if (m_endframe < m_startframe)
+ delta_time = -delta_time;
+
+ if (m_direction > 0)
+ m_localtime = m_startframe + delta_time;
+ else
+ m_localtime = m_endframe - delta_time;
+}
+
+bool KX_IpoActuator::Update(double curtime, bool frame)
+{
+ // result = true if animation has to be continued, false if animation stops
+ // maybe there are events for us in the queue !
+ bool bNegativeEvent = false;
+ int numevents = 0;
+
+ if (frame)
+ {
+ numevents = m_events.size();
+ for (vector<CValue*>::iterator i=m_events.end(); !(i==m_events.begin());)
+ {
+ --i;
+ if ((*i)->GetNumber() == 0.0f)
+ bNegativeEvent = true;
+
+ (*i)->Release();
+ }
+ m_events.clear();
+
+ if (m_type != KX_ACT_IPO_PLAY)
+ {
+ if (bNegativeEvent)
+ RemoveAllEvents();
+ }
+ }
+
+ double start_smaller_then_end = ( m_startframe < m_endframe ? 1.0 : -1.0);
+
+ bool result=true;
+ if (!bNegativeEvent)
+ {
+ if (m_starttime < -2.0*start_smaller_then_end*(m_endframe - m_startframe))
+ {
+ m_starttime = curtime - KX_KetsjiEngine::GetSuspendedDelta();
+ m_bIpoPlaying = true;
+ }
+ }
+
+ switch (m_type)
+ {
+
+ case KX_ACT_IPO_PLAY:
+ {
+ // Check if playing forwards. result = ! finished
+
+ if (!bNegativeEvent)
+ {
+ if (start_smaller_then_end > 0.0)
+ result = (m_localtime < m_endframe && !(m_localtime == m_startframe && bNegativeEvent));
+ else
+ result = (m_localtime > m_endframe && !(m_localtime == m_startframe && bNegativeEvent));
+ }
+ else
+ {
+ result = (m_bIpoPlaying && (m_localtime < m_endframe));
+ }
+
+ if (result)
+ {
+ SetLocalTime(curtime);
+
+ /* Perform clamping */
+ ClampLocalTime();
+
+ CIpoAction ipoaction(
+ (KX_GameObject*)GetParent(),
+ m_localtime,
+ m_recurse,
+ m_ipo_as_force,
+ m_force_ipo_local);
+ GetParent()->Execute(ipoaction);
+ } else
+ {
+ m_localtime=m_startframe;
+ SetStartTime(curtime);
+ m_direction=1;
+ }
+ break;
+ }
+ case KX_ACT_IPO_PINGPONG:
+ {
+ result = true;
+ if (bNegativeEvent && ((m_localtime == m_startframe )|| (m_localtime == m_endframe)))
+ result = false;
+ else
+ SetLocalTime(curtime);
+
+ if (ClampLocalTime())
+ {
+ result = false;
+ m_direction = -m_direction;
+ }
+
+ CIpoAction ipoaction(
+ (KX_GameObject*) GetParent(),
+ m_localtime,
+ m_recurse,
+ m_ipo_as_force,
+ m_force_ipo_local);
+ GetParent()->Execute(ipoaction);
+ break;
+ }
+ case KX_ACT_IPO_FLIPPER:
+ {
+ result = !(bNegativeEvent && (m_localtime == m_startframe));
+ if (numevents)
+ {
+ if (bNegativeEvent)
+ m_direction = -1;
+ else
+ m_direction = 1;
+ SetStartTime(curtime);
+ }
+
+ SetLocalTime(curtime);
+
+ if (ClampLocalTime() && m_localtime == m_startframe)
+ result = false;
+
+ CIpoAction ipoaction(
+ (KX_GameObject*) GetParent(),
+ m_localtime,
+ m_recurse,
+ m_ipo_as_force,
+ m_force_ipo_local);
+ GetParent()->Execute(ipoaction);
+ break;
+ }
+
+ case KX_ACT_IPO_LOOPSTOP:
+ {
+ if (numevents)
+ {
+ if (bNegativeEvent)
+ {
+ result = false;
+ m_bNegativeEvent = false;
+ numevents = 0;
+ }
+ SetStartTime(curtime);
+ } // fall through to loopend, and quit the ipo animation immediatly
+ }
+ case KX_ACT_IPO_LOOPEND:
+ {
+ if (numevents){
+ if (bNegativeEvent){
+ m_bNegativeEvent = true;
+ }
+ }
+
+ if (bNegativeEvent && m_localtime == m_startframe){
+ result = false;
+ }
+ else
+ {
+ if (m_localtime*start_smaller_then_end < m_endframe*start_smaller_then_end)
+ {
+ SetLocalTime(curtime);
+ }
+ else{
+ if (!m_bNegativeEvent){
+ /* Perform wraparound */
+ SetLocalTime(curtime);
+ m_localtime = m_startframe + fmod(m_localtime, m_startframe - m_endframe);
+ SetStartTime(curtime);
+ }
+ else
+ {
+ /* Perform clamping */
+ m_localtime=m_endframe;
+ result = false;
+ m_bNegativeEvent = false;
+ }
+ }
+ }
+
+ CIpoAction ipoaction(
+ (KX_GameObject*) GetParent(),
+ m_localtime,
+ m_recurse,
+ m_ipo_as_force,
+ m_force_ipo_local);
+ GetParent()->Execute(ipoaction);
+ break;
+ }
+
+ case KX_ACT_IPO_KEY2KEY:
+ {
+ // not implemented yet
+ result = false;
+ break;
+ }
+
+ case KX_ACT_IPO_FROM_PROP:
+ {
+ result = !bNegativeEvent;
+
+ CValue* propval = GetParent()->GetProperty(m_propname);
+ if (propval)
+ {
+ m_localtime = propval->GetNumber();
+
+ CIpoAction ipoaction(
+ (KX_GameObject*) GetParent(),
+ m_localtime,
+ m_recurse,
+ m_ipo_as_force,
+ m_force_ipo_local);
+ GetParent()->Execute(ipoaction);
+
+ } else
+ {
+ result = false;
+ }
+ break;
+ }
+
+ default:
+ result = false;
+ }
+
+ if (!result && m_type != KX_ACT_IPO_LOOPSTOP)
+ m_starttime = -2.0*start_smaller_then_end*(m_endframe - m_startframe) - 1.0;
+
+ return result;
+}
+
+KX_IpoActuator::IpoActType KX_IpoActuator::string2mode(char* modename) {
+ IpoActType res = KX_ACT_IPO_NODEF;
+
+ if (modename == S_KX_ACT_IPO_PLAY_STRING) {
+ res = KX_ACT_IPO_PLAY;
+ } else if (modename == S_KX_ACT_IPO_PINGPONG_STRING) {
+ res = KX_ACT_IPO_PINGPONG;
+ } else if (modename == S_KX_ACT_IPO_FLIPPER_STRING) {
+ res = KX_ACT_IPO_FLIPPER;
+ } else if (modename == S_KX_ACT_IPO_LOOPSTOP_STRING) {
+ res = KX_ACT_IPO_LOOPSTOP;
+ } else if (modename == S_KX_ACT_IPO_LOOPEND_STRING) {
+ res = KX_ACT_IPO_LOOPEND;
+ } else if (modename == S_KX_ACT_IPO_KEY2KEY_STRING) {
+ res = KX_ACT_IPO_KEY2KEY;
+ } else if (modename == S_KX_ACT_IPO_FROM_PROP_STRING) {
+ res = KX_ACT_IPO_FROM_PROP;
+ }
+
+ return res;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_IpoActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_IpoActuator",
+ sizeof(KX_IpoActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_IpoActuator::Parents[] = {
+ &KX_IpoActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_IpoActuator::Methods[] = {
+ {"set", (PyCFunction) KX_IpoActuator::sPySet,
+ METH_VARARGS, Set_doc},
+ {"setProperty", (PyCFunction) KX_IpoActuator::sPySetProperty,
+ METH_VARARGS, SetProperty_doc},
+ {"setStart", (PyCFunction) KX_IpoActuator::sPySetStart,
+ METH_VARARGS, SetStart_doc},
+ {"getStart", (PyCFunction) KX_IpoActuator::sPyGetStart,
+ METH_VARARGS, GetStart_doc},
+ {"setEnd", (PyCFunction) KX_IpoActuator::sPySetEnd,
+ METH_VARARGS, SetEnd_doc},
+ {"getEnd", (PyCFunction) KX_IpoActuator::sPyGetEnd,
+ METH_VARARGS, GetEnd_doc},
+ {"setIpoAsForce", (PyCFunction) KX_IpoActuator::sPySetIpoAsForce,
+ METH_VARARGS, SetIpoAsForce_doc},
+ {"getIpoAsForce", (PyCFunction) KX_IpoActuator::sPyGetIpoAsForce,
+ METH_VARARGS, GetIpoAsForce_doc},
+ {"setType", (PyCFunction) KX_IpoActuator::sPySetType,
+ METH_VARARGS, SetType_doc},
+ {"getType", (PyCFunction) KX_IpoActuator::sPyGetType,
+ METH_VARARGS, GetType_doc},
+ {"setForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPySetForceIpoActsLocal,
+ METH_VARARGS, SetForceIpoActsLocal_doc},
+ {"getForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPyGetForceIpoActsLocal,
+ METH_VARARGS, GetForceIpoActsLocal_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* KX_IpoActuator::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IActuator);
+}
+
+
+
+/* set --------------------------------------------------------------------- */
+char KX_IpoActuator::Set_doc[] =
+"set(mode, startframe, endframe, force?)\n"
+"\t - mode: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n"
+"\t - startframe: first frame to use (int)\n"
+"\t - endframe : last frame to use (int)\n"
+"\t - force? : interpret this ipo as a force? (KX_TRUE, KX_FALSE)"
+"\tSet the properties of the actuator.\n";
+PyObject* KX_IpoActuator::PySet(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ /* sets modes PLAY, PINGPONG, FLIPPER, LOOPSTOP, LOOPEND */
+ /* arg 1 = mode string, arg 2 = startframe, arg3 = stopframe, */
+ /* arg4 = force toggle */
+ char* mode;
+ int forceToggle;
+ IpoActType modenum;
+ int startFrame, stopFrame;
+ if(!PyArg_ParseTuple(args, "siii", &mode, &startFrame,
+ &stopFrame, &forceToggle)) {
+ return NULL;
+ }
+ modenum = string2mode(mode);
+
+ switch (modenum) {
+ case KX_ACT_IPO_PLAY:
+ case KX_ACT_IPO_PINGPONG:
+ case KX_ACT_IPO_FLIPPER:
+ case KX_ACT_IPO_LOOPSTOP:
+ case KX_ACT_IPO_LOOPEND:
+ m_type = modenum;
+ m_startframe = startFrame;
+ m_endframe = stopFrame;
+ m_ipo_as_force = PyArgToBool(forceToggle);
+ break;
+ default:
+ ; /* error */
+ }
+
+ Py_Return;
+}
+
+/* set property ----------------------------------------------------------- */
+char KX_IpoActuator::SetProperty_doc[] =
+"setProperty(propname)\n"
+"\t - propname: name of the property (string)\n"
+"\tSet the property to be used in FromProp mode.\n";
+PyObject* KX_IpoActuator::PySetProperty(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ /* mode is implicit here, but not supported yet... */
+ /* args: property */
+ char *propertyName;
+ if(!PyArg_ParseTuple(args, "s", &propertyName)) {
+ return NULL;
+ }
+
+ m_propname = propertyName;
+
+ Py_Return;
+}
+
+/* 4. setStart: */
+char KX_IpoActuator::SetStart_doc[] =
+"setStart(frame)\n"
+"\t - frame: first frame to use (int)\n"
+"\tSet the frame from which the ipo starts playing.\n";
+PyObject* KX_IpoActuator::PySetStart(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float startArg;
+ if(!PyArg_ParseTuple(args, "f", &startArg)) {
+ return NULL;
+ }
+
+ m_startframe = startArg;
+
+ Py_Return;
+}
+/* 5. getStart: */
+char KX_IpoActuator::GetStart_doc[] =
+"getStart()\n"
+"\tReturns the frame from which the ipo starts playing.\n";
+PyObject* KX_IpoActuator::PyGetStart(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return PyFloat_FromDouble(m_startframe);
+}
+
+/* 6. setEnd: */
+char KX_IpoActuator::SetEnd_doc[] =
+"setEnd(frame)\n"
+"\t - frame: last frame to use (int)\n"
+"\tSet the frame at which the ipo stops playing.\n";
+PyObject* KX_IpoActuator::PySetEnd(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float endArg;
+ if(!PyArg_ParseTuple(args, "f", &endArg)) {
+ return NULL;
+ }
+
+ m_endframe = endArg;
+
+ Py_Return;
+}
+/* 7. getEnd: */
+char KX_IpoActuator::GetEnd_doc[] =
+"getEnd()\n"
+"\tReturns the frame at which the ipo stops playing.\n";
+PyObject* KX_IpoActuator::PyGetEnd(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return PyFloat_FromDouble(m_endframe);
+}
+
+/* 6. setIpoAsForce: */
+char KX_IpoActuator::SetIpoAsForce_doc[] =
+"setIpoAsForce(force?)\n"
+"\t - force? : interpret this ipo as a force? (KX_TRUE, KX_FALSE)\n"
+"\tSet whether to interpret the ipo as a force rather than a displacement.\n";
+PyObject* KX_IpoActuator::PySetIpoAsForce(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int boolArg;
+
+ if (!PyArg_ParseTuple(args, "i", &boolArg)) {
+ return NULL;
+ }
+
+ m_ipo_as_force = PyArgToBool(boolArg);
+
+ Py_Return;
+}
+/* 7. getIpoAsForce: */
+char KX_IpoActuator::GetIpoAsForce_doc[] =
+"getIpoAsForce()\n"
+"\tReturns whether to interpret the ipo as a force rather than a displacement.\n";
+PyObject* KX_IpoActuator::PyGetIpoAsForce(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return BoolToPyArg(m_ipo_as_force);
+}
+
+/* 8. setType: */
+char KX_IpoActuator::SetType_doc[] =
+"setType(mode)\n"
+"\t - mode: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n"
+"\tSet the operation mode of the actuator.\n";
+PyObject* KX_IpoActuator::PySetType(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int typeArg;
+
+ if (!PyArg_ParseTuple(args, "i", &typeArg)) {
+ return NULL;
+ }
+
+ if ( (typeArg > KX_ACT_IPO_NODEF)
+ && (typeArg < KX_ACT_IPO_KEY2KEY) ) {
+ m_type = (IpoActType) typeArg;
+ }
+
+ Py_Return;
+}
+/* 9. getType: */
+char KX_IpoActuator::GetType_doc[] =
+"getType()\n"
+"\tReturns the operation mode of the actuator.\n";
+PyObject* KX_IpoActuator::PyGetType(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return PyInt_FromLong(m_type);
+}
+
+/* 10. setForceIpoActsLocal: */
+char KX_IpoActuator::SetForceIpoActsLocal_doc[] =
+"setForceIpoActsLocal(local?)\n"
+"\t - local? : Apply the ipo-as-force in the object's local\n"
+"\t coordinates? (KX_TRUE, KX_FALSE)\n"
+"\tSet whether to apply the force in the object's local\n"
+"\tcoordinates rather than the world global coordinates.\n";
+PyObject* KX_IpoActuator::PySetForceIpoActsLocal(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int boolArg;
+
+ if (!PyArg_ParseTuple(args, "i", &boolArg)) {
+ return NULL;
+ }
+
+ m_force_ipo_local = PyArgToBool(boolArg);
+
+ Py_Return;
+}
+/* 11. getForceIpoActsLocal: */
+char KX_IpoActuator::GetForceIpoActsLocal_doc[] =
+"getForceIpoActsLocal()\n"
+"\tReturn whether to apply the force in the object's local\n"
+"\tcoordinates rather than the world global coordinates.\n";
+PyObject* KX_IpoActuator::PyGetForceIpoActsLocal(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return BoolToPyArg(m_force_ipo_local);
+}
+
+
+/* eof */
diff --git a/source/gameengine/Ketsji/KX_IpoActuator.h b/source/gameengine/Ketsji/KX_IpoActuator.h
new file mode 100644
index 00000000000..9a7d1a92751
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_IpoActuator.h
@@ -0,0 +1,158 @@
+/**
+ * Do an object ipo
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_IPOACTUATOR
+#define __KX_IPOACTUATOR
+
+#include "SCA_IActuator.h"
+
+class KX_IpoActuator : public SCA_IActuator
+{
+ Py_Header;
+private:
+ /** Computes the IPO start time from the current time
+ and the current frame. */
+ void SetStartTime(float curtime);
+ /** Computes the current frame from the current time
+ and the IPO start time. */
+ void SetLocalTime(float curtime);
+ /** Ensures the current frame is between the start and
+ end frames. */
+ bool ClampLocalTime();
+
+protected:
+ bool m_bNegativeEvent;
+
+ /** Begin frame of the ipo. */
+ float m_startframe;
+
+ /** End frame of the ipo. */
+ float m_endframe;
+
+ /** Include children in the transforms? */
+ bool m_recurse;
+
+ /** Current active frame of the ipo. */
+ float m_localtime;
+
+ /** The time this ipo started at. */
+ float m_starttime;
+
+ /** play backwards or forwards? (positive means forward). */
+ float m_direction;
+
+ /** Name of the property (only used in from_prop mode). */
+ STR_String m_propname;
+
+ /** Interpret the ipo as a force? */
+ bool m_ipo_as_force;
+
+ /** Apply a force-ipo locally? */
+ bool m_force_ipo_local;
+
+ bool m_bIpoPlaying;
+
+public:
+ enum IpoActType
+ {
+ KX_ACT_IPO_NODEF = 0,
+ KX_ACT_IPO_PLAY,
+ KX_ACT_IPO_PINGPONG,
+ KX_ACT_IPO_FLIPPER,
+ KX_ACT_IPO_LOOPSTOP,
+ KX_ACT_IPO_LOOPEND,
+ KX_ACT_IPO_KEY2KEY,
+ KX_ACT_IPO_FROM_PROP,
+ KX_ACT_IPO_MAX
+ };
+
+ static STR_String S_KX_ACT_IPO_PLAY_STRING;
+ static STR_String S_KX_ACT_IPO_PINGPONG_STRING;
+ static STR_String S_KX_ACT_IPO_FLIPPER_STRING;
+ static STR_String S_KX_ACT_IPO_LOOPSTOP_STRING;
+ static STR_String S_KX_ACT_IPO_LOOPEND_STRING;
+ static STR_String S_KX_ACT_IPO_KEY2KEY_STRING;
+ static STR_String S_KX_ACT_IPO_FROM_PROP_STRING;
+
+ IpoActType string2mode(char* modename);
+
+ IpoActType m_type;
+
+ KX_IpoActuator(SCA_IObject* gameobj,
+ const STR_String& propname,
+ float starttime,
+ float endtime,
+ bool recurse,
+ int acttype,
+ bool ipo_as_force,
+ bool force_ipo_local,
+ PyTypeObject* T=&Type);
+ virtual ~KX_IpoActuator() {};
+
+ virtual CValue* GetReplica() {
+ KX_IpoActuator* replica = new KX_IpoActuator(*this);//m_float,GetName());
+ replica->ProcessReplica();
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+ };
+
+ void SetStart(float starttime);
+ void SetEnd(float endtime);
+ virtual bool Update(double curtime, bool frame);
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+ //KX_PYMETHOD_DOC
+ KX_PYMETHOD_DOC(KX_IpoActuator,Set);
+ KX_PYMETHOD_DOC(KX_IpoActuator,SetProperty);
+/* KX_PYMETHOD_DOC(KX_IpoActuator,SetKey2Key); */
+ KX_PYMETHOD_DOC(KX_IpoActuator,SetStart);
+ KX_PYMETHOD_DOC(KX_IpoActuator,GetStart);
+ KX_PYMETHOD_DOC(KX_IpoActuator,SetEnd);
+ KX_PYMETHOD_DOC(KX_IpoActuator,GetEnd);
+ KX_PYMETHOD_DOC(KX_IpoActuator,SetIpoAsForce);
+ KX_PYMETHOD_DOC(KX_IpoActuator,GetIpoAsForce);
+ KX_PYMETHOD_DOC(KX_IpoActuator,SetType);
+ KX_PYMETHOD_DOC(KX_IpoActuator,GetType);
+ KX_PYMETHOD_DOC(KX_IpoActuator,SetForceIpoActsLocal);
+ KX_PYMETHOD_DOC(KX_IpoActuator,GetForceIpoActsLocal);
+
+};
+
+#endif //__KX_IPOACTUATOR
+
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
new file mode 100644
index 00000000000..f8826245aab
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -0,0 +1,1469 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * The engine ties all game modules together.
+ */
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif //WIN32
+
+#include <iostream>
+
+#include "KX_KetsjiEngine.h"
+
+#include "ListValue.h"
+#include "IntValue.h"
+#include "VectorValue.h"
+#include "BoolValue.h"
+#include "FloatValue.h"
+
+#define KX_NUM_ITERATIONS 4
+#include "RAS_BucketManager.h"
+#include "RAS_Rect.h"
+#include "RAS_IRasterizer.h"
+#include "RAS_IRenderTools.h"
+#include "RAS_ICanvas.h"
+#include "STR_String.h"
+#include "MT_Vector3.h"
+#include "MT_Transform.h"
+#include "SCA_IInputDevice.h"
+#include "KX_Scene.h"
+#include "MT_CmMatrix4x4.h"
+#include "KX_Camera.h"
+#include "KX_PythonInit.h"
+#include "KX_PyConstraintBinding.h"
+#include "PHY_IPhysicsEnvironment.h"
+#include "SumoPhysicsEnvironment.h"
+
+#include "SND_Scene.h"
+#include "SND_IAudioDevice.h"
+
+#include "NG_NetworkScene.h"
+#include "NG_NetworkDeviceInterface.h"
+
+#include "KX_WorldInfo.h"
+#include "KX_ISceneConverter.h"
+#include "KX_TimeCategoryLogger.h"
+
+#include "RAS_FramingManager.h"
+
+// If define: little test for Nzc: guarded drawing. If the canvas is
+// not valid, skip rendering this frame.
+//#define NZC_GUARDED_OUTPUT
+#define DEFAULT_LOGIC_TIC_RATE 60.0
+#define DEFAULT_PHYSICS_TIC_RATE 60.0
+
+const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = {
+ "Physics:", // tc_physics
+ "Logic", // tc_logic
+ "Network:", // tc_network
+ "Scenegraph:", // tc_scenegraph
+ "Sound:", // tc_sound
+ "Rasterizer:", // tc_rasterizer
+ "Services:", // tc_services
+ "Overhead:", // tc_overhead
+ "Outside:" // tc_outside
+};
+
+double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE;
+
+double KX_KetsjiEngine::m_suspendedtime = 0.0;
+double KX_KetsjiEngine::m_suspendeddelta = 0.0;
+
+
+/**
+ * Constructor of the Ketsji Engine
+ */
+KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
+ : m_canvas(NULL),
+ m_rasterizer(NULL),
+ m_kxsystem(system),
+ m_rendertools(NULL),
+ m_sceneconverter(NULL),
+ m_networkdevice(NULL),
+ m_audiodevice(NULL),
+ m_pythondictionary(NULL),
+ m_keyboarddevice(NULL),
+ m_mousedevice(NULL),
+
+ m_propertiesPresent(false),
+
+ m_bInitialized(false),
+ m_activecam(0),
+ m_bFixedTime(false),
+ m_game2ipo(false),
+
+ m_firstframe(true),
+
+ m_frameTime(0.f),
+ m_clockTime(0.f),
+ m_previousClockTime(0.f),
+
+
+ m_exitcode(KX_EXIT_REQUEST_NO_REQUEST),
+ m_exitstring(""),
+
+ m_drawingmode(5),
+ m_cameraZoom(1.0),
+
+ m_overrideCam(false),
+ m_overrideCamUseOrtho(false),
+
+ m_stereo(false),
+ m_curreye(0),
+
+ m_logger(NULL),
+
+ // Set up timing info display variables
+ m_show_framerate(false),
+ m_show_profile(false),
+ m_showProperties(false),
+ m_showBackground(false),
+ m_show_debug_properties(false),
+
+ // Default behavior is to hide the cursor every frame.
+ m_hideCursor(false),
+
+ m_overrideFrameColor(false),
+ m_overrideFrameColorR(0.0),
+ m_overrideFrameColorG(0.0),
+ m_overrideFrameColorB(0.0)
+{
+ // Initialize the time logger
+ m_logger = new KX_TimeCategoryLogger (25);
+
+ for (int i = tc_first; i < tc_numCategories; i++)
+ m_logger->AddCategory((KX_TimeCategory)i);
+
+}
+
+
+
+/**
+ * Destructor of the Ketsji Engine, release all memory
+ */
+KX_KetsjiEngine::~KX_KetsjiEngine()
+{
+ delete m_logger;
+}
+
+
+
+void KX_KetsjiEngine::SetKeyboardDevice(SCA_IInputDevice* keyboarddevice)
+{
+ MT_assert(keyboarddevice);
+ m_keyboarddevice = keyboarddevice;
+}
+
+
+
+void KX_KetsjiEngine::SetMouseDevice(SCA_IInputDevice* mousedevice)
+{
+ MT_assert(mousedevice);
+ m_mousedevice = mousedevice;
+}
+
+
+
+void KX_KetsjiEngine::SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice)
+{
+ MT_assert(networkdevice);
+ m_networkdevice = networkdevice;
+}
+
+
+
+void KX_KetsjiEngine::SetAudioDevice(SND_IAudioDevice* audiodevice)
+{
+ MT_assert(audiodevice);
+ m_audiodevice = audiodevice;
+}
+
+
+
+void KX_KetsjiEngine::SetCanvas(RAS_ICanvas* canvas)
+{
+ MT_assert(canvas);
+ m_canvas = canvas;
+}
+
+
+
+void KX_KetsjiEngine::SetRenderTools(RAS_IRenderTools* rendertools)
+{
+ MT_assert(rendertools);
+ m_rendertools = rendertools;
+}
+
+
+
+void KX_KetsjiEngine::SetRasterizer(RAS_IRasterizer* rasterizer)
+{
+ MT_assert(rasterizer);
+ m_rasterizer = rasterizer;
+}
+
+
+
+void KX_KetsjiEngine::SetPythonDictionary(PyObject* pythondictionary)
+{
+ MT_assert(pythondictionary);
+ m_pythondictionary = pythondictionary;
+}
+
+
+
+void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter)
+{
+ MT_assert(sceneconverter);
+ m_sceneconverter = sceneconverter;
+}
+
+
+
+/**
+ * Ketsji Init(), Initializes datastructures and converts data from
+ * Blender into Ketsji native (realtime) format also sets up the
+ * graphics context
+ */
+void KX_KetsjiEngine::StartEngine(bool clearIpo)
+{
+ m_clockTime = m_kxsystem->GetTimeInSeconds();
+ m_frameTime = m_kxsystem->GetTimeInSeconds();
+ m_previousClockTime = m_kxsystem->GetTimeInSeconds();
+
+ m_firstframe = true;
+ m_bInitialized = true;
+ m_ticrate = DEFAULT_LOGIC_TIC_RATE;
+
+ if (m_game2ipo)
+ {
+ m_sceneconverter->ResetPhysicsObjectsAnimationIpo(clearIpo);
+ m_sceneconverter->WritePhysicsObjectToAnimationIpo(m_currentFrame);
+ }
+
+}
+
+bool KX_KetsjiEngine::BeginFrame()
+{
+ bool result = false;
+
+ RAS_Rect vp;
+ KX_Scene* firstscene = *m_scenes.begin();
+ const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
+
+ // set the area used for rendering
+ m_rasterizer->SetRenderArea();
+
+ RAS_FramingManager::ComputeViewport(framesettings, m_canvas->GetDisplayArea(), vp);
+
+ if (m_canvas->BeginDraw())
+ {
+ result = true;
+
+ m_canvas->SetViewPort(vp.GetLeft(), vp.GetBottom(), vp.GetRight(), vp.GetTop());
+ SetBackGround( firstscene->GetWorldInfo() );
+ m_rasterizer->BeginFrame( m_drawingmode , m_kxsystem->GetTimeInSeconds());
+ m_rendertools->BeginFrame( m_rasterizer);
+ }
+
+ return result;
+}
+
+
+void KX_KetsjiEngine::EndFrame()
+{
+ // Show profiling info
+ m_logger->StartLog(tc_overhead, m_kxsystem->GetTimeInSeconds(), true);
+ if (m_show_framerate || m_show_profile || (m_show_debug_properties && m_propertiesPresent))
+ {
+ RenderDebugProperties();
+ }
+ // Go to next profiling measurement, time spend after this call is shown in the next frame.
+ m_logger->NextMeasurement(m_kxsystem->GetTimeInSeconds());
+
+ m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
+ m_rasterizer->EndFrame();
+ // swap backbuffer (drawing into this buffer) <-> front/visible buffer
+ m_rasterizer->SwapBuffers();
+ m_rendertools->EndFrame(m_rasterizer);
+
+
+ m_canvas->EndDraw();
+
+
+}
+
+//#include "PIL_time.h"
+//#include "LinearMath/btQuickprof.h"
+
+
+bool KX_KetsjiEngine::NextFrame()
+{
+
+// static hidden::Clock sClock;
+
+m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true);
+
+//float dt = sClock.getTimeMicroseconds() * 0.000001f;
+//sClock.reset();
+
+if (m_bFixedTime)
+ m_clockTime += 1./m_ticrate;
+else
+{
+
+// m_clockTime += dt;
+ m_clockTime = m_kxsystem->GetTimeInSeconds();
+}
+
+ double deltatime = m_clockTime - m_frameTime;
+ if (deltatime<0.f)
+ {
+ printf("problem with clock\n");
+ deltatime = 0.f;
+ m_clockTime = 0.f;
+ m_frameTime = 0.f;
+ }
+
+
+ // Compute the number of logic frames to do each update (fixed tic bricks)
+ int frames =int(deltatime*m_ticrate);
+// if (frames>1)
+// printf("****************************************");
+// printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames);
+
+// if (!frames)
+// PIL_sleep_ms(1);
+
+ KX_SceneList::iterator sceneit;
+ int frameOut = 5;
+
+ if (frames>frameOut)
+ {
+
+ // printf("framedOut: %d\n",frames);
+ m_frameTime+=(frames-frameOut)*(1.0/m_ticrate);
+ frames = frameOut;
+ }
+
+
+ bool doRender = frames>0;
+
+ while (frames)
+ {
+
+
+ m_frameTime += 1.0/m_ticrate;
+
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
+ // for each scene, call the proceed functions
+ {
+ KX_Scene* scene = *sceneit;
+
+ /* Suspension holds the physics and logic processing for an
+ * entire scene. Objects can be suspended individually, and
+ * the settings for that preceed the logic and physics
+ * update. */
+ m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
+
+ m_sceneconverter->resetNoneDynamicObjectToIpo();//this is for none dynamic objects with ipo
+
+ scene->UpdateObjectActivity();
+
+ if (!scene->IsSuspended())
+ {
+ // if the scene was suspended recalcutlate the delta tu "curtime"
+ m_suspendedtime = scene->getSuspendedTime();
+ if (scene->getSuspendedTime()!=0.0)
+ scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
+ m_suspendeddelta = scene->getSuspendedDelta();
+
+
+ m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true);
+ scene->GetNetworkScene()->proceed(m_frameTime);
+
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateParents(m_frameTime);
+
+ m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
+ // set Python hooks for each scene
+ PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
+ PHY_SetActiveScene(scene);
+
+ scene->GetPhysicsEnvironment()->endFrame();
+
+ // Update scenegraph after physics step. This maps physics calculations
+ // into node positions.
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateParents(m_frameTime);
+
+ // Process sensors, and controllers
+ m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
+ scene->LogicBeginFrame(m_frameTime);
+
+ // Scenegraph needs to be updated again, because Logic Controllers
+ // can affect the local matrices.
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateParents(m_frameTime);
+
+ // Process actuators
+
+ // Do some cleanup work for this logic frame
+ m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
+ scene->LogicUpdateFrame(m_frameTime, true);
+
+ scene->LogicEndFrame();
+
+ // Actuators can affect the scenegraph
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateParents(m_frameTime);
+
+ m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
+ scene->GetPhysicsEnvironment()->beginFrame();
+
+ // Perform physics calculations on the scene. This can involve
+ // many iterations of the physics solver.
+ scene->GetPhysicsEnvironment()->proceedDeltaTime(m_frameTime,1.0/m_ticrate);//m_deltatimerealDeltaTime);
+
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateParents(m_frameTime);
+
+
+ if (m_game2ipo)
+ {
+ m_sceneconverter->WritePhysicsObjectToAnimationIpo(++m_currentFrame);
+ }
+
+ scene->setSuspendedTime(0.0);
+ } // suspended
+ else
+ if(scene->getSuspendedTime()==0.0)
+ scene->setSuspendedTime(m_clockTime);
+
+ DoSound(scene);
+
+ m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
+ }
+
+ // update system devices
+ m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
+ if (m_keyboarddevice)
+ m_keyboarddevice->NextFrame();
+
+ if (m_mousedevice)
+ m_mousedevice->NextFrame();
+
+ if (m_networkdevice)
+ m_networkdevice->NextFrame();
+
+ if (m_audiodevice)
+ m_audiodevice->NextFrame();
+
+ // scene management
+ ProcessScheduledScenes();
+
+ frames--;
+ }
+
+ bool bUseAsyncLogicBricks= false;//true;
+
+ if (bUseAsyncLogicBricks)
+ {
+ // Logic update sub frame: this will let some logic bricks run at the
+ // full frame rate.
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
+ // for each scene, call the proceed functions
+ {
+ KX_Scene* scene = *sceneit;
+
+ if (!scene->IsSuspended())
+ {
+ // if the scene was suspended recalcutlate the delta tu "curtime"
+ m_suspendedtime = scene->getSuspendedTime();
+ if (scene->getSuspendedTime()!=0.0)
+ scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
+ m_suspendeddelta = scene->getSuspendedDelta();
+
+ // set Python hooks for each scene
+ PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
+ PHY_SetActiveScene(scene);
+
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateParents(m_clockTime);
+
+ // Perform physics calculations on the scene. This can involve
+ // many iterations of the physics solver.
+ m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
+ scene->GetPhysicsEnvironment()->proceedDeltaTime(m_clockTime,0.f);
+ // Update scenegraph after physics step. This maps physics calculations
+ // into node positions.
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateParents(m_clockTime);
+
+ // Do some cleanup work for this logic frame
+ m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
+ scene->LogicUpdateFrame(m_clockTime, false);
+
+ // Actuators can affect the scenegraph
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateParents(m_clockTime);
+
+ scene->setSuspendedTime(0.0);
+ } // suspended
+ else
+ if(scene->getSuspendedTime()==0.0)
+ scene->setSuspendedTime(m_clockTime);
+
+ DoSound(scene);
+
+ m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
+ }
+ }
+
+
+ m_previousClockTime = m_clockTime;
+
+ // Start logging time spend outside main loop
+ m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true);
+
+ return doRender;
+}
+
+
+
+void KX_KetsjiEngine::Render()
+{
+ KX_Scene* firstscene = *m_scenes.begin();
+ const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
+
+ m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
+
+ // hiding mouse cursor each frame
+ // (came back when going out of focus and then back in again)
+ if (m_hideCursor)
+ m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
+
+ // clear the entire game screen with the border color
+ // only once per frame
+ m_canvas->BeginDraw();
+ if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED) {
+ m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
+ if (m_overrideFrameColor)
+ {
+ // Do not use the framing bar color set in the Blender scenes
+ m_canvas->ClearColor(
+ m_overrideFrameColorR,
+ m_overrideFrameColorG,
+ m_overrideFrameColorB,
+ 1.0
+ );
+ }
+ else
+ {
+ // Use the framing bar color set in the Blender scenes
+ m_canvas->ClearColor(
+ framesettings.BarRed(),
+ framesettings.BarGreen(),
+ framesettings.BarBlue(),
+ 1.0
+ );
+ }
+ // clear the -whole- viewport
+ m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER);
+ }
+
+ m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE);
+
+ // BeginFrame() sets the actual drawing area. You can use a part of the window
+ if (!BeginFrame())
+ return;
+
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
+ // for each scene, call the proceed functions
+ {
+ KX_Scene* scene = *sceneit;
+ KX_Camera* cam = scene->GetActiveCamera();
+ // pass the scene's worldsettings to the rasterizer
+ SetWorldSettings(scene->GetWorldInfo());
+
+ // Avoid drawing the scene with the active camera twice when it's viewport is enabled
+ if(!cam->GetViewport())
+ {
+ if (scene->IsClearingZBuffer())
+ m_rasterizer->ClearDepthBuffer();
+
+ m_rendertools->SetAuxilaryClientInfo(scene);
+
+ //Initialize scene viewport.
+ SetupRenderFrame(scene, cam);
+
+ // do the rendering
+ RenderFrame(scene, cam);
+ }
+
+ set<class KX_Camera*>* cameras = scene->GetCameras();
+
+ // Draw the scene once for each camera with an enabled viewport
+ set<KX_Camera*>::iterator it = cameras->begin();
+ while(it != cameras->end())
+ {
+ if((*it)->GetViewport())
+ {
+ if (scene->IsClearingZBuffer())
+ m_rasterizer->ClearDepthBuffer();
+
+ m_rendertools->SetAuxilaryClientInfo(scene);
+
+ //Initialize scene viewport.
+ SetupRenderFrame(scene, (*it));
+
+ // do the rendering
+ RenderFrame(scene, (*it));
+ }
+
+ it++;
+ }
+ }
+
+ // only one place that checks for stereo
+ if(m_rasterizer->Stereo())
+ {
+ m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_RIGHTEYE);
+
+ if (!BeginFrame())
+ return;
+
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
+ // for each scene, call the proceed functions
+ {
+ KX_Scene* scene = *sceneit;
+ KX_Camera* cam = scene->GetActiveCamera();
+
+ // pass the scene's worldsettings to the rasterizer
+ SetWorldSettings(scene->GetWorldInfo());
+
+ if (scene->IsClearingZBuffer())
+ m_rasterizer->ClearDepthBuffer();
+
+ //pass the scene, for picking and raycasting (shadows)
+ m_rendertools->SetAuxilaryClientInfo(scene);
+
+ //Initialize scene viewport.
+ //SetupRenderFrame(scene);
+ SetupRenderFrame(scene, cam);
+
+ // do the rendering
+ //RenderFrame(scene);
+ RenderFrame(scene, cam);
+ }
+ } // if(m_rasterizer->Stereo())
+
+ EndFrame();
+}
+
+
+
+void KX_KetsjiEngine::RequestExit(int exitrequestmode)
+{
+ m_exitcode = exitrequestmode;
+}
+
+
+
+void KX_KetsjiEngine::SetNameNextGame(const STR_String& nextgame)
+{
+ m_exitstring = nextgame;
+}
+
+
+
+int KX_KetsjiEngine::GetExitCode()
+{
+ // if a gameactuator has set an exitcode or if there are no scenes left
+ if (!m_exitcode)
+ {
+ if (m_scenes.begin()==m_scenes.end())
+ m_exitcode = KX_EXIT_REQUEST_NO_SCENES_LEFT;
+ }
+
+ return m_exitcode;
+}
+
+
+
+const STR_String& KX_KetsjiEngine::GetExitString()
+{
+ return m_exitstring;
+}
+
+
+
+void KX_KetsjiEngine::DoSound(KX_Scene* scene)
+{
+ m_logger->StartLog(tc_sound, m_kxsystem->GetTimeInSeconds(), true);
+
+ KX_Camera* cam = scene->GetActiveCamera();
+ if (!cam)
+ return;
+ MT_Point3 listenerposition = cam->NodeGetWorldPosition();
+ MT_Vector3 listenervelocity = cam->GetLinearVelocity();
+ MT_Matrix3x3 listenerorientation = cam->NodeGetWorldOrientation();
+
+ SND_Scene* soundscene = scene->GetSoundScene();
+ soundscene->SetListenerTransform(
+ listenerposition,
+ listenervelocity,
+ listenerorientation);
+
+ soundscene->Proceed();
+}
+
+
+
+void KX_KetsjiEngine::SetBackGround(KX_WorldInfo* wi)
+{
+ if (wi->hasWorld())
+ {
+ if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED)
+ {
+ m_rasterizer->SetBackColor(
+ wi->getBackColorRed(),
+ wi->getBackColorGreen(),
+ wi->getBackColorBlue(),
+ 0.0
+ );
+ }
+ }
+}
+
+
+
+void KX_KetsjiEngine::SetWorldSettings(KX_WorldInfo* wi)
+{
+ if (wi->hasWorld())
+ {
+ // ...
+ m_rasterizer->SetAmbientColor(
+ wi->getAmbientColorRed(),
+ wi->getAmbientColorGreen(),
+ wi->getAmbientColorBlue()
+ );
+
+ if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED)
+ {
+ if (wi->hasMist())
+ {
+ m_rasterizer->SetFog(
+ wi->getMistStart(),
+ wi->getMistDistance(),
+ wi->getMistColorRed(),
+ wi->getMistColorGreen(),
+ wi->getMistColorBlue()
+ );
+ }
+ else
+ {
+ m_rasterizer->DisableFog();
+ }
+ }
+ }
+}
+
+
+
+void KX_KetsjiEngine::SetDrawType(int drawingmode)
+{
+ m_drawingmode = drawingmode;
+}
+
+
+
+void KX_KetsjiEngine::EnableCameraOverride(const STR_String& forscene)
+{
+ m_overrideCam = true;
+ m_overrideSceneName = forscene;
+}
+
+
+
+void KX_KetsjiEngine::SetCameraZoom(float camzoom)
+{
+ m_cameraZoom = camzoom;
+}
+
+
+
+void KX_KetsjiEngine::SetCameraOverrideUseOrtho(bool useOrtho)
+{
+ m_overrideCamUseOrtho = useOrtho;
+}
+
+
+
+void KX_KetsjiEngine::SetCameraOverrideProjectionMatrix(const MT_CmMatrix4x4& mat)
+{
+ m_overrideCamProjMat = mat;
+}
+
+
+void KX_KetsjiEngine::SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat)
+{
+ m_overrideCamViewMat = mat;
+}
+
+
+void KX_KetsjiEngine::SetupRenderFrame(KX_Scene *scene, KX_Camera* cam)
+{
+ // In this function we make sure the rasterizer settings are upto
+ // date. We compute the viewport so that logic
+ // using this information is upto date.
+
+ // Note we postpone computation of the projection matrix
+ // so that we are using the latest camera position.
+
+ RAS_Rect viewport;
+
+ if (cam->GetViewport()) {
+ viewport.SetLeft(cam->GetViewportLeft());
+ viewport.SetBottom(cam->GetViewportBottom());
+ viewport.SetRight(cam->GetViewportRight());
+ viewport.SetTop(cam->GetViewportTop());
+ }
+ else if ( m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) {
+ RAS_FramingManager::ComputeViewport(
+ scene->GetFramingType(),
+ m_canvas->GetDisplayArea(),
+ viewport
+ );
+ } else {
+ viewport.SetLeft(0);
+ viewport.SetBottom(0);
+ viewport.SetRight(int(m_canvas->GetWidth()));
+ viewport.SetTop(int(m_canvas->GetHeight()));
+ }
+ // store the computed viewport in the scene
+
+ scene->SetSceneViewport(viewport);
+
+ // set the viewport for this frame and scene
+ m_canvas->SetViewPort(
+ viewport.GetLeft(),
+ viewport.GetBottom(),
+ viewport.GetRight(),
+ viewport.GetTop()
+ );
+
+}
+
+
+// update graphics
+void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
+{
+ float left, right, bottom, top, nearfrust, farfrust;
+ const float ortho = 100.0;
+// KX_Camera* cam = scene->GetActiveCamera();
+
+ if (!cam)
+ return;
+
+ // see KX_BlenderMaterial::Activate
+ //m_rasterizer->SetAmbient();
+ m_rasterizer->DisplayFog();
+
+ if (m_overrideCam && (scene->GetName() == m_overrideSceneName) && m_overrideCamUseOrtho) {
+ MT_CmMatrix4x4 projmat = m_overrideCamProjMat;
+ m_rasterizer->SetProjectionMatrix(projmat);
+ } else if (cam->hasValidProjectionMatrix() && !cam->GetViewport() )
+ {
+ m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix());
+ } else
+ {
+ RAS_FrameFrustum frustum;
+ float lens = cam->GetLens();
+ nearfrust = cam->GetCameraNear();
+ farfrust = cam->GetCameraFar();
+
+ if (!cam->GetCameraData()->m_perspective)
+ {
+ lens *= ortho;
+ nearfrust = (nearfrust + 1.0)*ortho;
+ farfrust *= ortho;
+ }
+
+ RAS_FramingManager::ComputeFrustum(
+ scene->GetFramingType(),
+ m_canvas->GetDisplayArea(),
+ scene->GetSceneViewport(),
+ lens,
+ nearfrust,
+ farfrust,
+ frustum
+ );
+
+ left = frustum.x1 * m_cameraZoom;
+ right = frustum.x2 * m_cameraZoom;
+ bottom = frustum.y1 * m_cameraZoom;
+ top = frustum.y2 * m_cameraZoom;
+ nearfrust = frustum.camnear;
+ farfrust = frustum.camfar;
+
+ MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
+ left, right, bottom, top, nearfrust, farfrust);
+
+ cam->SetProjectionMatrix(projmat);
+
+ // Otherwise the projection matrix for each eye will be the same...
+ if (m_rasterizer->Stereo())
+ cam->InvalidateProjectionMatrix();
+ }
+
+ MT_Transform camtrans(cam->GetWorldToCamera());
+ if (!cam->GetCameraData()->m_perspective)
+ camtrans.getOrigin()[2] *= ortho;
+ MT_Matrix4x4 viewmat(camtrans);
+
+ m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(),
+ cam->GetCameraLocation(), cam->GetCameraOrientation());
+ cam->SetModelviewMatrix(viewmat);
+
+ scene->UpdateMeshTransformations();
+
+ // The following actually reschedules all vertices to be
+ // redrawn. There is a cache between the actual rescheduling
+ // and this call though. Visibility is imparted when this call
+ // runs through the individual objects.
+ scene->CalculateVisibleMeshes(m_rasterizer,cam);
+
+ scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
+
+ m_rendertools->MotionBlur(m_rasterizer);
+
+}
+
+
+
+void KX_KetsjiEngine::StopEngine()
+{
+ if (m_bInitialized)
+ {
+
+ if (m_game2ipo)
+ {
+// printf("TestHandlesPhysicsObjectToAnimationIpo\n");
+ m_sceneconverter->TestHandlesPhysicsObjectToAnimationIpo();
+ }
+
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
+ {
+ KX_Scene* scene = *sceneit;
+ delete scene;
+ }
+ m_scenes.clear();
+
+ // cleanup all the stuff
+ m_rasterizer->Exit();
+ }
+}
+
+// Scene Management is able to switch between scenes
+// and have several scene's running in parallel
+void KX_KetsjiEngine::AddScene(KX_Scene* scene)
+{
+ m_scenes.push_back(scene);
+ PostProcessScene(scene);
+ SceneListsChanged();
+}
+
+
+
+void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
+{
+ bool override_camera = (m_overrideCam && (scene->GetName() == m_overrideSceneName));
+
+ // if there is no activecamera, or the camera is being
+ // overridden we need to construct a temporarily camera
+ if (!scene->GetActiveCamera() || override_camera)
+ {
+ KX_Camera* activecam = NULL;
+
+ RAS_CameraData camdata = RAS_CameraData();
+ activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata, false);
+ activecam->SetName("__default__cam__");
+
+ // set transformation
+ if (override_camera) {
+ const MT_CmMatrix4x4& cammatdata = m_overrideCamViewMat;
+ MT_Transform trans = MT_Transform(cammatdata.getPointer());
+ MT_Transform camtrans;
+ camtrans.invert(trans);
+
+ activecam->NodeSetLocalPosition(camtrans.getOrigin());
+ activecam->NodeSetLocalOrientation(camtrans.getBasis());
+ activecam->NodeUpdateGS(0,true);
+ } else {
+ activecam->NodeSetLocalPosition(MT_Point3(0.0, 0.0, 0.0));
+ activecam->NodeSetLocalOrientation(MT_Vector3(0.0, 0.0, 0.0));
+ activecam->NodeUpdateGS(0,true);
+ }
+
+ scene->AddCamera(activecam);
+ scene->SetActiveCamera(activecam);
+ scene->GetObjectList()->Add(activecam->AddRef());
+ scene->GetRootParentList()->Add(activecam->AddRef());
+ }
+
+ scene->UpdateParents(0.0);
+}
+
+
+
+void KX_KetsjiEngine::RenderDebugProperties()
+{
+ STR_String debugtxt;
+ int xcoord = 10; // mmmm, these constants were taken from blender source
+ int ycoord = 14; // to 'mimic' behaviour
+
+ float tottime = m_logger->GetAverage();
+ if (tottime < 1e-6f) {
+ tottime = 1e-6f;
+ }
+
+ // Set viewport to entire canvas
+ RAS_Rect viewport;
+ m_canvas->SetViewPort(0, 0, int(m_canvas->GetWidth()), int(m_canvas->GetHeight()));
+
+ /* Framerate display */
+ if (m_show_framerate) {
+ debugtxt.Format("swap : %.3f (%.3f frames per second)", tottime, 1.0/tottime);
+ m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
+ debugtxt.Ptr(),
+ xcoord,
+ ycoord,
+ m_canvas->GetWidth() /* RdV, TODO ?? */,
+ m_canvas->GetHeight() /* RdV, TODO ?? */);
+ ycoord += 14;
+ }
+
+ /* Profile and framerate display */
+ if (m_show_profile)
+ {
+ for (int j = tc_first; j < tc_numCategories; j++)
+ {
+ debugtxt.Format(m_profileLabels[j]);
+ m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
+ debugtxt.Ptr(),
+ xcoord,ycoord,
+ m_canvas->GetWidth(),
+ m_canvas->GetHeight());
+ double time = m_logger->GetAverage((KX_TimeCategory)j);
+ debugtxt.Format("%2.2f %%", time/tottime * 100.f);
+ m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
+ debugtxt.Ptr(),
+ xcoord + 60 ,ycoord,
+ m_canvas->GetWidth(),
+ m_canvas->GetHeight());
+ ycoord += 14;
+ }
+ }
+
+ /* Property display*/
+ if (m_show_debug_properties && m_propertiesPresent)
+ {
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
+ {
+ KX_Scene* scene = *sceneit;
+ /* the 'normal' debug props */
+ vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties();
+
+ for (vector<SCA_DebugProp*>::iterator it = debugproplist.begin();
+ !(it==debugproplist.end());it++)
+ {
+ CValue* propobj = (*it)->m_obj;
+ STR_String objname = propobj->GetName();
+ STR_String propname = (*it)->m_name;
+ CValue* propval = propobj->GetProperty(propname);
+ if (propval)
+ {
+ STR_String text = propval->GetText();
+ debugtxt = objname + "." + propname + " = " + text;
+ m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
+ debugtxt.Ptr(),
+ xcoord,
+ ycoord,
+ m_canvas->GetWidth(),
+ m_canvas->GetHeight());
+ ycoord += 14;
+ }
+ }
+ }
+ }
+}
+
+
+KX_SceneList* KX_KetsjiEngine::CurrentScenes()
+{
+ return &m_scenes;
+}
+
+
+
+KX_Scene* KX_KetsjiEngine::FindScene(const STR_String& scenename)
+{
+ KX_SceneList::iterator sceneit = m_scenes.begin();
+
+ // bit risky :) better to split the second clause
+ while ( (sceneit != m_scenes.end())
+ && ((*sceneit)->GetName() != scenename))
+ {
+ sceneit++;
+ }
+
+ return ((sceneit == m_scenes.end()) ? NULL : *sceneit);
+}
+
+
+
+void KX_KetsjiEngine::ConvertAndAddScene(const STR_String& scenename,bool overlay)
+{
+ // only add scene when it doesn't exist!
+ if (FindScene(scenename))
+ {
+ STR_String tmpname = scenename;
+ printf("warning: scene %s already exists, not added!\n",tmpname.Ptr());
+ }
+ else
+ {
+ if (overlay)
+ {
+ m_addingOverlayScenes.insert(scenename);
+ }
+ else
+ {
+ m_addingBackgroundScenes.insert(scenename);
+ }
+ }
+}
+
+
+
+
+void KX_KetsjiEngine::RemoveScene(const STR_String& scenename)
+{
+ if (FindScene(scenename))
+ {
+ m_removingScenes.insert(scenename);
+ }
+ else
+ {
+// STR_String tmpname = scenename;
+ std::cout << "warning: scene " << scenename << " does not exist, not removed!" << std::endl;
+ }
+}
+
+
+
+void KX_KetsjiEngine::RemoveScheduledScenes()
+{
+ if (m_removingScenes.size())
+ {
+ set<STR_String>::iterator scenenameit;
+ for (scenenameit=m_removingScenes.begin();scenenameit != m_removingScenes.end();scenenameit++)
+ {
+ STR_String scenename = *scenenameit;
+
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
+ {
+ KX_Scene* scene = *sceneit;
+ if (scene->GetName()==scenename)
+ {
+ delete scene;
+ m_scenes.erase(sceneit);
+ break;
+ }
+ }
+ }
+ m_removingScenes.clear();
+ }
+}
+
+
+
+KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename)
+{
+
+ KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice,
+ m_mousedevice,
+ m_networkdevice,
+ m_audiodevice,
+ scenename);
+
+ m_sceneconverter->ConvertScene(scenename,
+ tmpscene,
+ m_pythondictionary,
+ m_keyboarddevice,
+ m_rendertools,
+ m_canvas);
+
+ return tmpscene;
+}
+
+
+
+void KX_KetsjiEngine::AddScheduledScenes()
+{
+ set<STR_String>::iterator scenenameit;
+
+ if (m_addingOverlayScenes.size())
+ {
+ for (scenenameit = m_addingOverlayScenes.begin();
+ scenenameit != m_addingOverlayScenes.end();
+ scenenameit++)
+ {
+ STR_String scenename = *scenenameit;
+ KX_Scene* tmpscene = CreateScene(scenename);
+ m_scenes.push_back(tmpscene);
+ PostProcessScene(tmpscene);
+ }
+ m_addingOverlayScenes.clear();
+ }
+
+ if (m_addingBackgroundScenes.size())
+ {
+ for (scenenameit = m_addingBackgroundScenes.begin();
+ scenenameit != m_addingBackgroundScenes.end();
+ scenenameit++)
+ {
+ STR_String scenename = *scenenameit;
+ KX_Scene* tmpscene = CreateScene(scenename);
+ m_scenes.insert(m_scenes.begin(),tmpscene);
+ PostProcessScene(tmpscene);
+
+ }
+ m_addingBackgroundScenes.clear();
+ }
+}
+
+
+
+void KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene)
+{
+ m_replace_scenes.insert(std::make_pair(oldscene,newscene));
+}
+
+// replace scene is not the same as removing and adding because the
+// scene must be in exact the same place (to maintain drawingorder)
+// (nzc) - should that not be done with a scene-display list? It seems
+// stupid to rely on the mem allocation order...
+void KX_KetsjiEngine::ReplaceScheduledScenes()
+{
+ if (m_replace_scenes.size())
+ {
+ set<pair<STR_String,STR_String> >::iterator scenenameit;
+
+ for (scenenameit = m_replace_scenes.begin();
+ scenenameit != m_replace_scenes.end();
+ scenenameit++)
+ {
+ STR_String oldscenename = (*scenenameit).first;
+ STR_String newscenename = (*scenenameit).second;
+ int i=0;
+ /* Scenes are not supposed to be included twice... I think */
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
+ {
+ KX_Scene* scene = *sceneit;
+ if (scene->GetName() == oldscenename)
+ {
+ delete scene;
+ KX_Scene* tmpscene = CreateScene(newscenename);
+ m_scenes[i]=tmpscene;
+ PostProcessScene(tmpscene);
+ }
+ i++;
+ }
+ }
+ m_replace_scenes.clear();
+ }
+}
+
+
+
+void KX_KetsjiEngine::SuspendScene(const STR_String& scenename)
+{
+ KX_Scene* scene = FindScene(scenename);
+ if (scene) scene->Suspend();
+}
+
+
+
+void KX_KetsjiEngine::ResumeScene(const STR_String& scenename)
+{
+ KX_Scene* scene = FindScene(scenename);
+ if (scene) scene->Resume();
+}
+
+
+
+void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime)
+{
+ m_bFixedTime = bUseFixedTime;
+}
+
+
+void KX_KetsjiEngine::SetGame2IpoMode(bool game2ipo,int startFrame)
+{
+ m_game2ipo = game2ipo;
+ if (game2ipo)
+ {
+ //when recording physics keyframes, always run at a fixed framerate
+ m_bFixedTime = true;
+ }
+ m_currentFrame = startFrame;
+}
+
+bool KX_KetsjiEngine::GetUseFixedTime(void) const
+{
+ return m_bFixedTime;
+}
+
+double KX_KetsjiEngine::GetSuspendedDelta()
+{
+ return m_suspendeddelta;
+}
+
+double KX_KetsjiEngine::GetTicRate()
+{
+ return m_ticrate;
+}
+
+void KX_KetsjiEngine::SetTicRate(double ticrate)
+{
+ m_ticrate = ticrate;
+}
+
+void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties)
+{
+ m_show_framerate = frameRate;
+ m_show_profile = profile;
+ m_show_debug_properties = properties;
+}
+
+
+
+void KX_KetsjiEngine::GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const
+{
+ frameRate = m_show_framerate;
+ profile = m_show_profile;
+ properties = m_show_debug_properties;
+}
+
+
+
+void KX_KetsjiEngine::ProcessScheduledScenes(void)
+{
+ // Check whether there will be changes to the list of scenes
+ if (m_addingOverlayScenes.size() ||
+ m_addingBackgroundScenes.size() ||
+ m_replace_scenes.size() ||
+ m_removingScenes.size()) {
+
+ // Change the scene list
+ ReplaceScheduledScenes();
+ RemoveScheduledScenes();
+ AddScheduledScenes();
+
+ // Notify
+ SceneListsChanged();
+ }
+}
+
+
+
+void KX_KetsjiEngine::SceneListsChanged(void)
+{
+ m_propertiesPresent = false;
+ KX_SceneList::iterator sceneit = m_scenes.begin();
+ while ((sceneit != m_scenes.end()) && (!m_propertiesPresent))
+ {
+ KX_Scene* scene = *sceneit;
+ vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties();
+ m_propertiesPresent = !debugproplist.empty();
+ sceneit++;
+ }
+}
+
+
+void KX_KetsjiEngine::SetHideCursor(bool hideCursor)
+{
+ m_hideCursor = hideCursor;
+}
+
+
+bool KX_KetsjiEngine::GetHideCursor(void) const
+{
+ return m_hideCursor;
+}
+
+
+void KX_KetsjiEngine::SetUseOverrideFrameColor(bool overrideFrameColor)
+{
+ m_overrideFrameColor = overrideFrameColor;
+}
+
+
+bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const
+{
+ return m_overrideFrameColor;
+}
+
+
+void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b)
+{
+ m_overrideFrameColorR = r;
+ m_overrideFrameColorG = g;
+ m_overrideFrameColorB = b;
+}
+
+
+void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
+{
+ r = m_overrideFrameColorR;
+ g = m_overrideFrameColorG;
+ b = m_overrideFrameColorB;
+}
+
+
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h
new file mode 100644
index 00000000000..16b53b6b688
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h
@@ -0,0 +1,344 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_KETSJI_ENGINE
+#define __KX_KETSJI_ENGINE
+
+#include "MT_CmMatrix4x4.h"
+#include "MT_Matrix4x4.h"
+#include "STR_String.h"
+#include "KX_ISystem.h"
+#include "KX_Scene.h"
+#include "KX_Python.h"
+#include "KX_WorldInfo.h"
+#include <vector>
+#include <set>
+
+class KX_TimeCategoryLogger;
+
+#define LEFT_EYE 1
+#define RIGHT_EYE 2
+
+enum KX_ExitRequestMode
+{
+ KX_EXIT_REQUEST_NO_REQUEST = 0,
+ KX_EXIT_REQUEST_QUIT_GAME,
+ KX_EXIT_REQUEST_RESTART_GAME,
+ KX_EXIT_REQUEST_START_OTHER_GAME,
+ KX_EXIT_REQUEST_NO_SCENES_LEFT,
+ KX_EXIT_REQUEST_BLENDER_ESC,
+ KX_EXIT_REQUEST_OUTSIDE,
+ KX_EXIT_REQUEST_MAX
+};
+
+/**
+ * KX_KetsjiEngine is the core game engine class.
+ */
+class KX_KetsjiEngine
+{
+
+private:
+ class RAS_ICanvas* m_canvas; // 2D Canvas (2D Rendering Device Context)
+ class RAS_IRasterizer* m_rasterizer; // 3D Rasterizer (3D Rendering)
+ class KX_ISystem* m_kxsystem;
+ class RAS_IRenderTools* m_rendertools;
+ class KX_ISceneConverter* m_sceneconverter;
+ class NG_NetworkDeviceInterface* m_networkdevice;
+ class SND_IAudioDevice* m_audiodevice;
+ PyObject* m_pythondictionary;
+ class SCA_IInputDevice* m_keyboarddevice;
+ class SCA_IInputDevice* m_mousedevice;
+
+ /** Lists of scenes scheduled to be removed at the end of the frame. */
+ std::set<STR_String> m_removingScenes;
+ /** Lists of overley scenes scheduled to be added at the end of the frame. */
+ std::set<STR_String> m_addingOverlayScenes;
+ /** Lists of background scenes scheduled to be added at the end of the frame. */
+ std::set<STR_String> m_addingBackgroundScenes;
+ /** Lists of scenes scheduled to be replaced at the end of the frame. */
+ std::set<std::pair<STR_String,STR_String> > m_replace_scenes;
+
+ /* The current list of scenes. */
+ KX_SceneList m_scenes;
+ /* State variable recording the presence of object debug info in the current scene list. */
+ bool m_propertiesPresent;
+
+ bool m_bInitialized;
+ int m_activecam;
+ bool m_bFixedTime;
+
+
+ bool m_firstframe;
+ int m_currentFrame;
+
+ double m_frameTime;//discrete timestamp of the 'game logic frame'
+ double m_clockTime;//current time
+ double m_previousClockTime;//previous clock time
+ double m_remainingTime;
+
+ static double m_ticrate;
+
+ static double m_suspendedtime;
+ static double m_suspendeddelta;
+
+ int m_exitcode;
+ STR_String m_exitstring;
+ /**
+ * Some drawing parameters, the drawing mode
+ * (wire/flat/texture), and the camera zoom
+ * factor.
+ */
+ int m_drawingmode;
+ float m_cameraZoom;
+
+ bool m_overrideCam;
+ STR_String m_overrideSceneName;
+
+ bool m_overrideCamUseOrtho;
+ MT_CmMatrix4x4 m_overrideCamProjMat;
+ MT_CmMatrix4x4 m_overrideCamViewMat;
+
+ bool m_stereo;
+ int m_curreye;
+
+ /** Categories for profiling display. */
+ typedef enum
+ {
+ tc_first = 0,
+ tc_physics = 0,
+ tc_logic,
+ tc_network,
+ tc_scenegraph,
+ tc_sound,
+ tc_rasterizer,
+ tc_services, // time spend in miscelaneous activities
+ tc_overhead, // profile info drawing overhead
+ tc_outside, // time spend outside main loop
+ tc_numCategories
+ } KX_TimeCategory;
+
+ /** Time logger. */
+ KX_TimeCategoryLogger* m_logger;
+
+ /** Labels for profiling display. */
+ static const char m_profileLabels[tc_numCategories][15];
+ /** Show the framerate on the game display? */
+ bool m_show_framerate;
+ /** Show profiling info on the game display? */
+ bool m_show_profile;
+ /** Show any debug (scene) object properties on the game display? */
+ bool m_showProperties;
+ /** Show background behind text for readability? */
+ bool m_showBackground;
+
+ bool m_show_debug_properties;
+
+ /** record physics into keyframes */
+ bool m_game2ipo;
+
+ /** Hide cursor every frame? */
+ bool m_hideCursor;
+
+ /** Override framing bars color? */
+ bool m_overrideFrameColor;
+ /** Red component of framing bar color. */
+ float m_overrideFrameColorR;
+ /** Green component of framing bar color. */
+ float m_overrideFrameColorG;
+ /** Blue component of framing bar color. */
+ float m_overrideFrameColorB;
+
+ void SetupRenderFrame(KX_Scene *scene, KX_Camera* cam);
+ void RenderFrame(KX_Scene* scene, KX_Camera* cam);
+ void RenderDebugProperties();
+ void SetBackGround(KX_WorldInfo* worldinfo);
+ void SetWorldSettings(KX_WorldInfo* worldinfo);
+ void DoSound(KX_Scene* scene);
+
+public:
+
+ KX_KetsjiEngine(class KX_ISystem* system);
+ virtual ~KX_KetsjiEngine();
+
+ // set the devices and stuff. the client must take care of creating these
+ void SetKeyboardDevice(SCA_IInputDevice* keyboarddevice);
+ void SetMouseDevice(SCA_IInputDevice* mousedevice);
+ void SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice);
+ void SetAudioDevice(SND_IAudioDevice* audiodevice);
+ void SetCanvas(RAS_ICanvas* canvas);
+ void SetRenderTools(RAS_IRenderTools* rendertools);
+ void SetRasterizer(RAS_IRasterizer* rasterizer);
+ void SetPythonDictionary(PyObject* pythondictionary);
+ void SetSceneConverter(KX_ISceneConverter* sceneconverter);
+ void SetGame2IpoMode(bool game2ipo,int startFrame);
+
+ ///returns true if an update happened to indicate -> Render
+ bool NextFrame();
+ void Render();
+
+ void StartEngine(bool clearIpo);
+ void StopEngine();
+ void Export(const STR_String& filename);
+
+ void RequestExit(int exitrequestmode);
+ void SetNameNextGame(const STR_String& nextgame);
+ int GetExitCode();
+ const STR_String& GetExitString();
+
+ KX_SceneList* CurrentScenes();
+ KX_Scene* FindScene(const STR_String& scenename);
+ void AddScene(class KX_Scene* scene);
+ void ConvertAndAddScene(const STR_String& scenename,bool overlay);
+
+ void RemoveScene(const STR_String& scenename);
+ void ReplaceScene(const STR_String& oldscene,const STR_String& newscene);
+ void SuspendScene(const STR_String& scenename);
+ void ResumeScene(const STR_String& scenename);
+
+ void SetDrawType(int drawingtype);
+ void SetCameraZoom(float camzoom);
+
+ void EnableCameraOverride(const STR_String& forscene);
+
+ void SetCameraOverrideUseOrtho(bool useOrtho);
+ void SetCameraOverrideProjectionMatrix(const MT_CmMatrix4x4& mat);
+ void SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat);
+
+ /**
+ * Sets display of all frames.
+ * @param bUseFixedTime New setting for display all frames.
+ */
+ void SetUseFixedTime(bool bUseFixedTime);
+
+ /**
+ * Returns display of all frames.
+ * @return Current setting for display all frames.
+ */
+ bool GetUseFixedTime(void) const;
+
+ /**
+ * Returns the difference between the local time of the scene (when it
+ * was running and not suspended) and the "curtime"
+ */
+ static double GetSuspendedDelta();
+
+ /**
+ * Gets the number of logic updates per second.
+ */
+ static double GetTicRate();
+ /**
+ * Sets the number of logic updates per second.
+ */
+ static void SetTicRate(double ticrate);
+
+ /**
+ * Activates or deactivates timing information display.
+ * @param frameRate Display for frame rate on or off.
+ * @param profile Display for individual components on or off.
+ * @param properties Display of scene object debug properties on or off.
+ */
+ void SetTimingDisplay(bool frameRate, bool profile, bool properties);
+
+ /**
+ * Returns status of timing information display.
+ * @param frameRate Display for frame rate on or off.
+ * @param profile Display for individual components on or off.
+ * @param properties Display of scene object debug properties on or off.
+ */
+ void GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const;
+
+ /**
+ * Sets cursor hiding on every frame.
+ * @param hideCursor Turns hiding on or off.
+ */
+ void SetHideCursor(bool hideCursor);
+
+ /**
+ * Returns the current setting for cursor hiding.
+ * @return The current setting for cursor hiding.
+ */
+ bool GetHideCursor(void) const;
+
+ /**
+ * Enables/disables the use of the framing bar color of the Blender file's scenes.
+ * @param overrideFrameColor The new setting.
+ */
+ void SetUseOverrideFrameColor(bool overrideFrameColor);
+
+ /**
+ * Enables/disables the use of the framing bar color of the Blender file's scenes.
+ * @param useSceneFrameColor The new setting.
+ */
+ bool GetUseOverrideFrameColor(void) const;
+
+ /**
+ * Set the color used for framing bar color instead of the one in the Blender file's scenes.
+ * @param r Red component of the override color.
+ * @param g Green component of the override color.
+ * @param b Blue component of the override color.
+ */
+ void SetOverrideFrameColor(float r, float g, float b);
+
+ /**
+ * Returns the color used for framing bar color instead of the one in the Blender file's scenes.
+ * @param r Red component of the override color.
+ * @param g Green component of the override color.
+ * @param b Blue component of the override color.
+ */
+ void GetOverrideFrameColor(float& r, float& g, float& b) const;
+
+protected:
+ /**
+ * Processes all scheduled scene activity.
+ * At the end, if the scene lists have changed,
+ * SceneListsChanged(void) is called.
+ * @see SceneListsChanged(void).
+ */
+ void ProcessScheduledScenes(void);
+
+ /**
+ * This method is invoked when the scene lists have changed.
+ */
+ void SceneListsChanged(void);
+
+ void RemoveScheduledScenes(void);
+ void AddScheduledScenes(void);
+ void ReplaceScheduledScenes(void);
+ void PostProcessScene(class KX_Scene* scene);
+ KX_Scene* CreateScene(const STR_String& scenename);
+
+ bool BeginFrame();
+ void EndFrame();
+};
+
+#endif //__KX_KETSJI_ENGINE
+
diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp
new file mode 100644
index 00000000000..4a92ea4ac13
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_Light.cpp
@@ -0,0 +1,263 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 (disable : 4786)
+#endif
+
+#include "KX_Light.h"
+#include "RAS_IRenderTools.h"
+
+#include "KX_PyMath.h"
+
+
+KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,
+ class RAS_IRenderTools* rendertools,
+ const RAS_LightObject& lightobj,
+ PyTypeObject* T
+ )
+ :
+ KX_GameObject(sgReplicationInfo,callbacks,T),
+ m_rendertools(rendertools)
+{
+ m_lightobj = lightobj;
+ m_lightobj.m_worldmatrix = GetOpenGLMatrixPtr();
+ m_rendertools->AddLight(&m_lightobj);
+};
+
+
+KX_LightObject::~KX_LightObject()
+{
+
+ m_rendertools->RemoveLight(&m_lightobj);
+}
+
+
+CValue* KX_LightObject::GetReplica()
+{
+
+ KX_LightObject* replica = new KX_LightObject(*this);
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ ProcessReplica(replica);
+
+ replica->m_lightobj.m_worldmatrix = replica->GetOpenGLMatrixPtr();
+ m_rendertools->AddLight(&replica->m_lightobj);
+ return replica;
+}
+
+PyObject* KX_LightObject::_getattr(const STR_String& attr)
+{
+ if (attr == "layer")
+ return PyInt_FromLong(m_lightobj.m_layer);
+
+ if (attr == "energy")
+ return PyFloat_FromDouble(m_lightobj.m_energy);
+
+ if (attr == "distance")
+ return PyFloat_FromDouble(m_lightobj.m_distance);
+
+ if (attr == "colour" || attr == "color")
+ return Py_BuildValue("[fff]", m_lightobj.m_red, m_lightobj.m_green, m_lightobj.m_blue);
+
+ if (attr == "lin_attenuation")
+ return PyFloat_FromDouble(m_lightobj.m_att1);
+
+ if (attr == "quad_attenuation")
+ return PyFloat_FromDouble(m_lightobj.m_att2);
+
+ if (attr == "spotsize")
+ return PyFloat_FromDouble(m_lightobj.m_spotsize);
+
+ if (attr == "spotblend")
+ return PyFloat_FromDouble(m_lightobj.m_spotblend);
+
+ if (attr == "SPOT")
+ return PyInt_FromLong(RAS_LightObject::LIGHT_SPOT);
+
+ if (attr == "SUN")
+ return PyInt_FromLong(RAS_LightObject::LIGHT_SUN);
+
+ if (attr == "NORMAL")
+ return PyInt_FromLong(RAS_LightObject::LIGHT_NORMAL);
+
+ if (attr == "type")
+ return PyInt_FromLong(m_lightobj.m_type);
+
+ _getattr_up(KX_GameObject);
+}
+
+int KX_LightObject::_setattr(const STR_String& attr, PyObject *pyvalue)
+{
+ if (attr == "SPOT" || attr == "SUN" || attr == "NORMAL")
+ {
+ PyErr_Format(PyExc_RuntimeError, "Attribute %s is read only.", attr.ReadPtr());
+ return 1;
+ }
+
+ if (PyInt_Check(pyvalue))
+ {
+ int value = PyInt_AsLong(pyvalue);
+ if (attr == "layer")
+ {
+ m_lightobj.m_layer = value;
+ return 0;
+ }
+
+ if (attr == "type")
+ {
+ if (value >= RAS_LightObject::LIGHT_SPOT && value <= RAS_LightObject::LIGHT_NORMAL)
+ m_lightobj.m_type = (RAS_LightObject::LightType) value;
+ return 0;
+ }
+ }
+
+ if (PyFloat_Check(pyvalue))
+ {
+ float value = PyFloat_AsDouble(pyvalue);
+ if (attr == "energy")
+ {
+ m_lightobj.m_energy = value;
+ return 0;
+ }
+
+ if (attr == "distance")
+ {
+ m_lightobj.m_distance = value;
+ return 0;
+ }
+
+ if (attr == "lin_attenuation")
+ {
+ m_lightobj.m_att1 = value;
+ return 0;
+ }
+
+ if (attr == "quad_attenuation")
+ {
+ m_lightobj.m_att2 = value;
+ return 0;
+ }
+
+ if (attr == "spotsize")
+ {
+ m_lightobj.m_spotsize = value;
+ return 0;
+ }
+
+ if (attr == "spotblend")
+ {
+ m_lightobj.m_spotblend = value;
+ return 0;
+ }
+ }
+
+ if (PySequence_Check(pyvalue))
+ {
+ if (attr == "colour" || attr == "color")
+ {
+ MT_Vector3 color;
+ if (PyVecTo(pyvalue, color))
+ {
+ m_lightobj.m_red = color[0];
+ m_lightobj.m_green = color[1];
+ m_lightobj.m_blue = color[2];
+ return 0;
+ }
+ return 1;
+ }
+ }
+
+ return KX_GameObject::_setattr(attr, pyvalue);
+}
+
+PyMethodDef KX_LightObject::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+char KX_LightObject::doc[] = "Module KX_LightObject\n\n"
+"Constants:\n"
+"\tSPOT\n"
+"\tSUN\n"
+"\tNORMAL\n"
+"Attributes:\n"
+"\ttype -> SPOT, SUN or NORMAL\n"
+"\t\tThe type of light.\n"
+"\tlayer -> integer bit field.\n"
+"\t\tThe layers this light applies to.\n"
+"\tenergy -> float.\n"
+"\t\tThe brightness of the light.\n"
+"\tdistance -> float.\n"
+"\t\tThe effect radius of the light.\n"
+"\tcolour -> list [r, g, b].\n"
+"\tcolor -> list [r, g, b].\n"
+"\t\tThe colour of the light.\n"
+"\tlin_attenuation -> float.\n"
+"\t\tThe attenuation factor for the light.\n"
+"\tspotsize -> float.\n"
+"\t\tThe size of the spot.\n"
+"\tspotblend -> float.\n"
+"\t\tThe blend? of the spot.\n";
+
+PyTypeObject KX_LightObject::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_LightObject",
+ sizeof(KX_LightObject),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0, 0,
+ doc
+};
+
+PyParentObject KX_LightObject::Parents[] = {
+ &KX_LightObject::Type,
+ &KX_GameObject::Type,
+ &SCA_IObject::Type,
+ &CValue::Type,
+ NULL
+};
diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h
new file mode 100644
index 00000000000..11fe7155c82
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_Light.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef __KX_LIGHT
+#define __KX_LIGHT
+
+#include "RAS_LightObject.h"
+#include "KX_GameObject.h"
+
+class KX_LightObject : public KX_GameObject
+{
+ Py_Header;
+protected:
+ RAS_LightObject m_lightobj;
+ class RAS_IRenderTools* m_rendertools; //needed for registering and replication of lightobj
+ static char doc[];
+
+public:
+ KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,class RAS_IRenderTools* rendertools,const struct RAS_LightObject& lightobj, PyTypeObject *T = &Type);
+ virtual ~KX_LightObject();
+ virtual CValue* GetReplica();
+ RAS_LightObject* GetLightData() { return &m_lightobj;}
+
+ virtual PyObject* _getattr(const STR_String& attr); /* lens, near, far, projection_matrix */
+ virtual int _setattr(const STR_String& attr, PyObject *pyvalue);
+};
+
+#endif //__KX_LIGHT
+
diff --git a/source/gameengine/Ketsji/KX_LightIpoSGController.cpp b/source/gameengine/Ketsji/KX_LightIpoSGController.cpp
new file mode 100644
index 00000000000..45865b7a682
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_LightIpoSGController.cpp
@@ -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 *****
+ */
+
+#include "KX_LightIpoSGController.h"
+#include "KX_ScalarInterpolator.h"
+#include "KX_Light.h"
+#include "RAS_LightObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(_WIN64)
+typedef unsigned __int64 uint_ptr;
+#else
+typedef unsigned long uint_ptr;
+#endif
+
+bool KX_LightIpoSGController::Update(double currentTime)
+{
+ if (m_modified)
+ {
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ (*i)->Execute(m_ipotime);//currentTime);
+ }
+
+ RAS_LightObject *lightobj;
+
+ SG_Spatial* ob = (SG_Spatial*)m_pObject;
+ KX_LightObject* kxlight = (KX_LightObject*) ob->GetSGClientObject();
+ lightobj = kxlight->GetLightData();
+ //lightobj = (KX_Light*)
+
+ if (m_modify_energy) {
+ lightobj->m_energy = m_energy;
+ }
+
+ if (m_modify_color) {
+ lightobj->m_red = m_col_rgb[0];
+ lightobj->m_green = m_col_rgb[1];
+ lightobj->m_blue = m_col_rgb[2];
+ }
+
+ if (m_modify_dist) {
+ lightobj->m_distance = m_dist;
+ }
+
+ m_modified=false;
+ }
+ return false;
+}
+
+
+void KX_LightIpoSGController::AddInterpolator(KX_IInterpolator* interp)
+{
+ this->m_interpolators.push_back(interp);
+}
+
+SG_Controller* KX_LightIpoSGController::GetReplica(class SG_Node* destnode)
+{
+ KX_LightIpoSGController* iporeplica = new KX_LightIpoSGController(*this);
+ // clear object that ipo acts on
+ iporeplica->ClearObject();
+
+ // dirty hack, ask Gino for a better solution in the ipo implementation
+ // hacken en zagen, in what we call datahiding, not written for replication :(
+
+ T_InterpolatorList oldlist = m_interpolators;
+ iporeplica->m_interpolators.clear();
+
+ T_InterpolatorList::iterator i;
+ for (i = oldlist.begin(); !(i == oldlist.end()); ++i) {
+ KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i));
+ iporeplica->AddInterpolator(copyipo);
+
+ MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget();
+ uint_ptr orgbase = (uint_ptr)this;
+ uint_ptr orgloc = (uint_ptr)scaal;
+ uint_ptr offset = orgloc-orgbase;
+ uint_ptr newaddrbase = (uint_ptr)iporeplica + offset;
+ MT_Scalar* blaptr = (MT_Scalar*) newaddrbase;
+ copyipo->SetNewTarget((MT_Scalar*)blaptr);
+ }
+
+ return iporeplica;
+}
+
+KX_LightIpoSGController::~KX_LightIpoSGController()
+{
+
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ delete (*i);
+ }
+
+}
diff --git a/source/gameengine/Ketsji/KX_LightIpoSGController.h b/source/gameengine/Ketsji/KX_LightIpoSGController.h
new file mode 100644
index 00000000000..deba37540d5
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_LightIpoSGController.h
@@ -0,0 +1,101 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 KX_LIGHTIPOSGCONTROLLER_H
+#define KX_LIGHTIPOSGCONTROLLER_H
+
+#include "SG_Controller.h"
+#include "SG_Spatial.h"
+
+#include "KX_IInterpolator.h"
+
+struct RAS_LightObject;
+
+class KX_LightIpoSGController : public SG_Controller
+{
+public:
+ MT_Scalar m_energy;
+ MT_Scalar m_col_rgb[3];
+ MT_Scalar m_dist;
+
+private:
+ T_InterpolatorList m_interpolators;
+ unsigned short m_modify_energy : 1;
+ unsigned short m_modify_color : 1;
+ unsigned short m_modify_dist : 1;
+ bool m_modified;
+
+ double m_ipotime;
+public:
+ KX_LightIpoSGController() :
+ m_modify_energy(false),
+ m_modify_color(false),
+ m_modify_dist(false),
+ m_modified(true),
+ m_ipotime(0.0)
+ {}
+
+ virtual ~KX_LightIpoSGController();
+
+ virtual SG_Controller* GetReplica(class SG_Node* destnode);
+
+ virtual bool Update(double time);
+
+ virtual void SetSimulatedTime(double time) {
+ m_ipotime = time;
+ m_modified = true;
+ }
+
+ void SetModifyEnergy(bool modify) {
+ m_modify_energy = modify;
+ }
+
+ void SetModifyColor(bool modify) {
+ m_modify_color = modify;
+ }
+
+ void SetModifyDist(bool modify) {
+ m_modify_dist = modify;
+ }
+
+ void
+ SetOption(
+ int option,
+ int value
+ ){
+ // intentionally empty
+ };
+
+ void AddInterpolator(KX_IInterpolator* interp);
+};
+
+#endif // KX_LIGHTIPOSGCONTROLLER_H
+
diff --git a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp
new file mode 100644
index 00000000000..c0757a32b9c
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp
@@ -0,0 +1,98 @@
+
+#include "KX_MaterialIpoController.h"
+#include "KX_ScalarInterpolator.h"
+#include "KX_GameObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+bool KX_MaterialIpoController::Update(double currentTime)
+{
+ if (m_modified)
+ {
+ m_rgba[0]=0;
+ m_rgba[1]=0;
+ m_rgba[2]=0;
+ m_rgba[3]=0;
+
+ m_specrgb[0] =0;
+ m_specrgb[1] =0;
+ m_specrgb[2] =0;
+ m_hard =0;
+ m_spec=0;
+ m_ref=0;
+ m_emit=0;
+ m_alpha = 0;
+
+
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ (*i)->Execute(m_ipotime);
+ }
+
+
+ SG_Spatial* ob = (SG_Spatial*)m_pObject;
+ KX_GameObject* kxgameobj= (KX_GameObject*) ob->GetSGClientObject();
+
+ //kxgameobj->SetObjectColor(m_rgba);
+ kxgameobj->UpdateMaterialData(
+ m_rgba,
+ m_specrgb,
+ m_hard,
+ m_spec,
+ m_ref,
+ m_emit,
+ m_alpha
+ );
+
+ m_modified=false;
+ }
+ return false;
+}
+
+
+void KX_MaterialIpoController::AddInterpolator(KX_IInterpolator* interp)
+{
+ this->m_interpolators.push_back(interp);
+}
+
+SG_Controller* KX_MaterialIpoController::GetReplica(class SG_Node* destnode)
+{
+ KX_MaterialIpoController* iporeplica = new KX_MaterialIpoController(*this);
+ // clear object that ipo acts on
+ iporeplica->ClearObject();
+
+ // dirty hack, ask Gino for a better solution in the ipo implementation
+ // hacken en zagen, in what we call datahiding, not written for replication :(
+
+ T_InterpolatorList oldlist = m_interpolators;
+ iporeplica->m_interpolators.clear();
+
+ T_InterpolatorList::iterator i;
+ for (i = oldlist.begin(); !(i == oldlist.end()); ++i) {
+ KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i));
+ iporeplica->AddInterpolator(copyipo);
+
+ MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget();
+ long orgbase = (long)this;
+ long orgloc = (long)scaal;
+ long offset = orgloc-orgbase;
+ long newaddrbase = (long)iporeplica + offset;
+ MT_Scalar* blaptr = (MT_Scalar*) newaddrbase;
+ copyipo->SetNewTarget((MT_Scalar*)blaptr);
+ }
+
+ return iporeplica;
+}
+
+KX_MaterialIpoController::~KX_MaterialIpoController()
+{
+
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ delete (*i);
+ }
+
+}
+
diff --git a/source/gameengine/Ketsji/KX_MaterialIpoController.h b/source/gameengine/Ketsji/KX_MaterialIpoController.h
new file mode 100644
index 00000000000..e76ddeefb04
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_MaterialIpoController.h
@@ -0,0 +1,54 @@
+#ifndef __KX_MATERIALIPOCONTROLLER_H__
+#define __KX_MATERIALIPOCONTROLLER_H__
+
+
+
+#include "SG_Controller.h"
+#include "SG_Spatial.h"
+#include "KX_IInterpolator.h"
+
+class KX_MaterialIpoController : public SG_Controller
+{
+public:
+ MT_Vector4 m_rgba;
+ MT_Vector3 m_specrgb;
+ MT_Scalar m_hard;
+ MT_Scalar m_spec;
+ MT_Scalar m_ref;
+ MT_Scalar m_emit;
+ MT_Scalar m_alpha;
+
+private:
+ T_InterpolatorList m_interpolators;
+ bool m_modified;
+
+ double m_ipotime;
+public:
+ KX_MaterialIpoController() :
+ m_modified(true),
+ m_ipotime(0.0)
+ {}
+ virtual ~KX_MaterialIpoController();
+ virtual SG_Controller* GetReplica(class SG_Node* destnode);
+ virtual bool Update(double time);
+ virtual void SetSimulatedTime(double time) {
+ m_ipotime = time;
+ m_modified = true;
+ }
+
+ void
+ SetOption(
+ int option,
+ int value
+ ){
+ // intentionally empty
+ };
+
+
+ void AddInterpolator(KX_IInterpolator* interp);
+};
+
+
+
+
+#endif//__KX_MATERIALIPOCONTROLLER_H__
diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp
new file mode 100644
index 00000000000..ebca3e13d7f
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_MeshProxy.cpp
@@ -0,0 +1,233 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_MeshProxy.h"
+#include "RAS_IPolygonMaterial.h"
+#include "RAS_MeshObject.h"
+
+#include "KX_VertexProxy.h"
+
+#include "KX_PolygonMaterial.h"
+#include "KX_BlenderMaterial.h"
+
+#include "KX_PyMath.h"
+#include "KX_ConvertPhysicsObject.h"
+
+PyTypeObject KX_MeshProxy::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_MeshProxy",
+ sizeof(KX_MeshProxy),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_MeshProxy::Parents[] = {
+ &KX_MeshProxy::Type,
+ &SCA_IObject::Type,
+ &CValue::Type,
+ &PyObjectPlus::Type,
+ NULL
+};
+
+PyMethodDef KX_MeshProxy::Methods[] = {
+{"getNumMaterials", (PyCFunction)KX_MeshProxy::sPyGetNumMaterials,METH_VARARGS},
+{"getMaterialName", (PyCFunction)KX_MeshProxy::sPyGetMaterialName,METH_VARARGS},
+{"getTextureName", (PyCFunction)KX_MeshProxy::sPyGetTextureName,METH_VARARGS},
+{"getVertexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetVertexArrayLength,METH_VARARGS},
+{"getVertex", (PyCFunction)KX_MeshProxy::sPyGetVertex,METH_VARARGS},
+KX_PYMETHODTABLE(KX_MeshProxy, reinstancePhysicsMesh),
+//{"getIndexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetIndexArrayLength,METH_VARARGS},
+
+ {NULL,NULL} //Sentinel
+};
+
+void KX_MeshProxy::SetMeshModified(bool v)
+{
+ m_meshobj->SetMeshModified(v);
+}
+
+
+PyObject*
+KX_MeshProxy::_getattr(const STR_String& attr)
+{
+ if (attr == "materials")
+ {
+ PyObject *materials = PyList_New(0);
+ RAS_MaterialBucket::Set::iterator mit = m_meshobj->GetFirstMaterial();
+ for(; mit != m_meshobj->GetLastMaterial(); ++mit)
+ {
+ RAS_IPolyMaterial *polymat = (*mit)->GetPolyMaterial();
+ if(polymat->GetFlag() & RAS_BLENDERMAT)
+ {
+ KX_BlenderMaterial *mat = static_cast<KX_BlenderMaterial*>(polymat);
+ PyList_Append(materials, mat);
+ }else
+ {
+ PyList_Append(materials, static_cast<KX_PolygonMaterial*>(polymat));
+ }
+ }
+ return materials;
+ }
+ _getattr_up(SCA_IObject);
+}
+
+
+
+KX_MeshProxy::KX_MeshProxy(RAS_MeshObject* mesh)
+ : m_meshobj(mesh)
+{
+}
+
+KX_MeshProxy::~KX_MeshProxy()
+{
+}
+
+
+
+// stuff for cvalue related things
+CValue* KX_MeshProxy::Calc(VALUE_OPERATOR op, CValue *val) { return NULL;}
+CValue* KX_MeshProxy::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) { return NULL;}
+
+const STR_String & KX_MeshProxy::GetText() {return m_meshobj->GetName();};
+float KX_MeshProxy::GetNumber() { return -1;}
+STR_String KX_MeshProxy::GetName() { return m_meshobj->GetName();}
+void KX_MeshProxy::SetName(STR_String name) { };
+CValue* KX_MeshProxy::GetReplica() { return NULL;}
+void KX_MeshProxy::ReplicaSetName(STR_String name) {};
+
+
+// stuff for python integration
+
+PyObject* KX_MeshProxy::PyGetNumMaterials(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int num = m_meshobj->NumMaterials();
+ return PyInt_FromLong(num);
+}
+
+PyObject* KX_MeshProxy::PyGetMaterialName(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int matid= 1;
+ STR_String matname;
+
+ if (PyArg_ParseTuple(args,"i",&matid))
+ {
+ matname = m_meshobj->GetMaterialName(matid);
+ }
+
+ return PyString_FromString(matname.Ptr());
+
+}
+
+
+PyObject* KX_MeshProxy::PyGetTextureName(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int matid= 1;
+ STR_String matname;
+
+ if (PyArg_ParseTuple(args,"i",&matid))
+ {
+ matname = m_meshobj->GetTextureName(matid);
+ }
+
+ return PyString_FromString(matname.Ptr());
+
+}
+
+PyObject* KX_MeshProxy::PyGetVertexArrayLength(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int matid= -1;
+ int length = -1;
+
+
+ if (PyArg_ParseTuple(args,"i",&matid))
+ {
+ RAS_IPolyMaterial* mat = m_meshobj->GetMaterialBucket(matid)->GetPolyMaterial();
+ if (mat)
+ {
+ length = m_meshobj->GetVertexArrayLength(mat);
+ }
+ }
+
+ return PyInt_FromLong(length);
+
+}
+
+
+PyObject* KX_MeshProxy::PyGetVertex(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int vertexindex= 1;
+ int matindex= 1;
+ PyObject* vertexob = NULL;
+
+ if (PyArg_ParseTuple(args,"ii",&matindex,&vertexindex))
+ {
+ RAS_TexVert* vertex = m_meshobj->GetVertex(matindex,vertexindex);
+ if (vertex)
+ {
+ vertexob = new KX_VertexProxy(this, vertex);
+ }
+ }
+
+ return vertexob;
+
+}
+
+KX_PYMETHODDEF_DOC(KX_MeshProxy, reinstancePhysicsMesh,
+"Reinstance the physics mesh.")
+{
+ //this needs to be reviewed, it is dependend on Sumo/Solid. Who is using this ?
+ return Py_None;//Py_Success(KX_ReInstanceShapeFromMesh(m_meshobj));
+}
diff --git a/source/gameengine/Ketsji/KX_MeshProxy.h b/source/gameengine/Ketsji/KX_MeshProxy.h
new file mode 100644
index 00000000000..9a8aa2a6f33
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_MeshProxy.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 __KX_MESHPROXY
+#define __KX_MESHPROXY
+
+#include "SCA_IObject.h"
+
+class KX_MeshProxy : public SCA_IObject
+{
+ Py_Header;
+
+ class RAS_MeshObject* m_meshobj;
+public:
+ KX_MeshProxy(class RAS_MeshObject* mesh);
+ virtual ~KX_MeshProxy();
+
+ void SetMeshModified(bool v);
+
+ // stuff for cvalue related things
+ virtual CValue* Calc(VALUE_OPERATOR op, CValue *val) ;
+ virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+ virtual const STR_String & GetText();
+ virtual float GetNumber();
+ virtual STR_String GetName();
+ virtual void SetName(STR_String name); // Set the name of the value
+ virtual void ReplicaSetName(STR_String name);
+ virtual CValue* GetReplica();
+
+// stuff for python integration
+ virtual PyObject* _getattr(const STR_String& attr);
+ KX_PYMETHOD(KX_MeshProxy,GetNumMaterials);
+ KX_PYMETHOD(KX_MeshProxy,GetMaterialName);
+ KX_PYMETHOD(KX_MeshProxy,GetTextureName);
+
+ // both take materialid (int)
+ KX_PYMETHOD(KX_MeshProxy,GetVertexArrayLength);
+ KX_PYMETHOD(KX_MeshProxy,GetVertex);
+ KX_PYMETHOD_DOC(KX_MeshProxy, reinstancePhysicsMesh);
+};
+
+#endif //__KX_MESHPROXY
+
diff --git a/source/gameengine/Ketsji/KX_MotionState.cpp b/source/gameengine/Ketsji/KX_MotionState.cpp
new file mode 100644
index 00000000000..cd01c0466cd
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_MotionState.cpp
@@ -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 *****
+ */
+#include "KX_MotionState.h"
+#include "SG_Spatial.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_MotionState::KX_MotionState(SG_Spatial* node) : m_node(node)
+{
+
+}
+
+KX_MotionState::~KX_MotionState()
+{
+}
+
+void KX_MotionState::getWorldPosition(float& posX,float& posY,float& posZ)
+{
+ MT_Point3 pos = m_node->GetWorldPosition();
+ posX = pos[0];
+ posY = pos[1];
+ posZ = pos[2];
+}
+
+void KX_MotionState::getWorldScaling(float& scaleX,float& scaleY,float& scaleZ)
+{
+ MT_Vector3 scale = m_node->GetWorldScaling();
+ scaleX = scale[0];
+ scaleY = scale[1];
+ scaleZ = scale[2];
+}
+
+void KX_MotionState::getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal)
+{
+ MT_Quaternion orn = m_node->GetWorldOrientation().getRotation();
+ quatIma0 = orn[0];
+ quatIma1 = orn[1];
+ quatIma2 = orn[2];
+ quatReal = orn[3];
+}
+
+void KX_MotionState::setWorldPosition(float posX,float posY,float posZ)
+{
+ m_node->SetLocalPosition(MT_Point3(posX,posY,posZ));
+ m_node->SetWorldPosition(MT_Point3(posX,posY,posZ));
+}
+
+void KX_MotionState::setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal)
+{
+ MT_Quaternion orn;
+ orn[0] = quatIma0;
+ orn[1] = quatIma1;
+ orn[2] = quatIma2;
+ orn[3] = quatReal;
+
+ m_node->SetLocalOrientation(orn);
+ m_node->SetWorldOrientation(orn);
+
+}
+
+void KX_MotionState::calculateWorldTransformations()
+{
+ m_node->ComputeWorldTransforms(NULL);
+}
+
+
diff --git a/source/gameengine/Ketsji/KX_MotionState.h b/source/gameengine/Ketsji/KX_MotionState.h
new file mode 100644
index 00000000000..d62dc1ed097
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_MotionState.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 __KX_MOTIONSTATE
+#define __KX_MOTIONSTATE
+
+#include "PHY_IMotionState.h"
+
+class KX_MotionState : public PHY_IMotionState
+{
+ class SG_Spatial* m_node;
+
+public:
+ KX_MotionState(class SG_Spatial* spatial);
+ virtual ~KX_MotionState();
+
+ virtual void getWorldPosition(float& posX,float& posY,float& posZ);
+ virtual void getWorldScaling(float& scaleX,float& scaleY,float& scaleZ);
+ virtual void getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal);
+ virtual void setWorldPosition(float posX,float posY,float posZ);
+ virtual void setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal);
+
+ virtual void calculateWorldTransformations();
+};
+
+#endif //__KX_MOTIONSTATE
+
diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
new file mode 100644
index 00000000000..431efa07e0a
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.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.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * KX_MouseFocusSensor determines mouse in/out/over events.
+ */
+
+#ifdef WIN32
+// This warning tells us about truncation of __long__ stl-generated names.
+// It can occasionally cause DevStudio to have internal compiler warnings.
+#pragma warning( disable : 4786 )
+#endif
+
+#include "MT_Point3.h"
+#include "RAS_FramingManager.h"
+#include "RAS_ICanvas.h"
+#include "RAS_IRasterizer.h"
+#include "SCA_IScene.h"
+#include "KX_Scene.h"
+#include "KX_Camera.h"
+#include "KX_MouseFocusSensor.h"
+
+#include "KX_RayCast.h"
+#include "KX_IPhysicsController.h"
+#include "PHY_IPhysicsController.h"
+#include "PHY_IPhysicsEnvironment.h"
+
+
+#include "KX_ClientObjectInfo.h"
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr,
+ int startx,
+ int starty,
+ short int mousemode,
+ int focusmode,
+ RAS_ICanvas* canvas,
+ KX_Scene* kxscene,
+ SCA_IObject* gameobj,
+ PyTypeObject* T)
+ : SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj, T),
+ m_focusmode(focusmode),
+ m_gp_canvas(canvas),
+ m_kxscene(kxscene)
+{
+
+ m_mouse_over_in_previous_frame = false;
+ m_positive_event = false;
+ m_hitObject = 0;
+
+}
+
+bool KX_MouseFocusSensor::Evaluate(CValue* event)
+{
+ bool result = false;
+ bool obHasFocus = false;
+
+// cout << "evaluate focus mouse sensor "<<endl;
+
+ if (m_focusmode) {
+ /* Focus behaviour required. Test mouse-on. The rest is
+ * equivalent to handling a key. */
+ obHasFocus = ParentObjectHasFocus();
+
+ if (!obHasFocus) {
+ if (m_mouse_over_in_previous_frame) {
+ m_positive_event = false;
+ result = true;
+ }
+ } else {
+ if (!m_mouse_over_in_previous_frame) {
+ m_positive_event = true;
+ result = true;
+ }
+ }
+ } else {
+ /* No focus behaviour required: revert to the basic mode. This
+ * mode is never used, because the converter never makes this
+ * sensor for a mouse-key event. It is here for
+ * completeness. */
+ result = SCA_MouseSensor::Evaluate(event);
+ m_positive_event = (m_val!=0);
+ }
+
+ m_mouse_over_in_previous_frame = obHasFocus;
+
+ return result;
+}
+
+bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data)
+{
+ KX_GameObject* hitKXObj = client_info->m_gameobject;
+
+ if (client_info->m_type > KX_ClientObjectInfo::ACTOR)
+ {
+ // false hit
+ return false;
+ }
+
+ /* Is this me? In the ray test, there are a lot of extra checks
+ * for aliasing artefacts from self-hits. That doesn't happen
+ * here, so a simple test suffices. Or does the camera also get
+ * self-hits? (No, and the raysensor shouldn't do it either, since
+ * self-hits are excluded by setting the correct ignore-object.)
+ * Hitspots now become valid. */
+ KX_GameObject* thisObj = (KX_GameObject*) GetParent();
+ if ((m_focusmode == 2) || hitKXObj == thisObj)
+ {
+ m_hitObject = hitKXObj;
+ m_hitPosition = hit_point;
+ m_hitNormal = hit_normal;
+ return true;
+ }
+
+ return true; // object must be visible to trigger
+ //return false; // occluded objects can trigger
+}
+
+
+
+bool KX_MouseFocusSensor::ParentObjectHasFocus(void)
+{
+ m_hitObject = 0;
+ m_hitPosition = MT_Vector3(0,0,0);
+ m_hitNormal = MT_Vector3(1,0,0);
+ MT_Point3 resultpoint;
+ MT_Vector3 resultnormal;
+
+ /* All screen handling in the gameengine is done by GL,
+ * specifically the model/view and projection parts. The viewport
+ * part is in the creator.
+ *
+ * The theory is this:
+ * WCS - world coordinates
+ * -> wcs_camcs_trafo ->
+ * camCS - camera coordinates
+ * -> camcs_clip_trafo ->
+ * clipCS - normalized device coordinates?
+ * -> normview_win_trafo
+ * winCS - window coordinates
+ *
+ * The first two transforms are respectively the model/view and
+ * the projection matrix. These are passed to the rasterizer, and
+ * we store them in the camera for easy access.
+ *
+ * For normalized device coords (xn = x/w, yn = y/w/zw) the
+ * windows coords become (lb = left bottom)
+ *
+ * xwin = [(xn + 1.0) * width]/2 + x_lb
+ * ywin = [(yn + 1.0) * height]/2 + y_lb
+ *
+ * Inverting (blender y is flipped!):
+ *
+ * xn = 2(xwin - x_lb)/width - 1.0
+ * yn = 2(ywin - y_lb)/height - 1.0
+ * = 2(height - y_blender - y_lb)/height - 1.0
+ * = 1.0 - 2(y_blender - y_lb)/height
+ *
+ * */
+
+ /* Because we don't want to worry about resize events, camera
+ * changes and all that crap, we just determine this over and
+ * over. Stop whining. We have lots of other calculations to do
+ * here as well. These reads are not the main cost. If there is no
+ * canvas, the test is irrelevant. The 1.0 makes sure the
+ * calculations don't bomb. Maybe we should explicitly guard for
+ * division by 0.0...*/
+
+ /**
+ * Get the scenes current viewport.
+ */
+
+ const RAS_Rect & viewport = m_kxscene->GetSceneViewport();
+
+ float height = float(viewport.m_y2 - viewport.m_y1 + 1);
+ float width = float(viewport.m_x2 - viewport.m_x1 + 1);
+
+ float x_lb = float(viewport.m_x1);
+ float y_lb = float(viewport.m_y1);
+
+ KX_Camera* cam = m_kxscene->GetActiveCamera();
+ /* There's some strangeness I don't fully get here... These values
+ * _should_ be wrong! */
+
+ /* old: */
+ float nearclip = 0.0;
+ float farclip = 1.0;
+
+ /* build the from and to point in normalized device coordinates
+ * Looks like normailized device coordinates are [-1,1] in x [-1,1] in y
+ * [0,-1] in z
+ *
+ * The actual z coordinates used don't have to be exact just infront and
+ * behind of the near and far clip planes.
+ */
+ MT_Vector4 frompoint = MT_Vector4(
+ (2 * (m_x-x_lb) / width) - 1.0,
+ 1.0 - (2 * (m_y - y_lb) / height),
+ nearclip,
+ 1.0
+ );
+ MT_Vector4 topoint = MT_Vector4(
+ (2 * (m_x-x_lb) / width) - 1.0,
+ 1.0 - (2 * (m_y-y_lb) / height),
+ farclip,
+ 1.0
+ );
+
+ /* camera to world */
+ MT_Transform wcs_camcs_tranform = cam->GetWorldToCamera();
+ if (!cam->GetCameraData()->m_perspective)
+ wcs_camcs_tranform.getOrigin()[2] *= 100.0;
+ MT_Transform cams_wcs_transform;
+ cams_wcs_transform.invert(wcs_camcs_tranform);
+
+ MT_Matrix4x4 camcs_wcs_matrix = MT_Matrix4x4(cams_wcs_transform);
+
+ /* badly defined, the first time round.... I wonder why... I might
+ * want to guard against floating point errors here.*/
+ MT_Matrix4x4 clip_camcs_matrix = MT_Matrix4x4(cam->GetProjectionMatrix());
+ clip_camcs_matrix.invert();
+
+ /* shoot-points: clip to cam to wcs . win to clip was already done.*/
+ frompoint = clip_camcs_matrix * frompoint;
+ topoint = clip_camcs_matrix * topoint;
+ frompoint = camcs_wcs_matrix * frompoint;
+ topoint = camcs_wcs_matrix * topoint;
+
+ /* from hom wcs to 3d wcs: */
+ MT_Point3 frompoint3 = MT_Point3(frompoint[0]/frompoint[3],
+ frompoint[1]/frompoint[3],
+ frompoint[2]/frompoint[3]);
+ MT_Point3 topoint3 = MT_Point3(topoint[0]/topoint[3],
+ topoint[1]/topoint[3],
+ topoint[2]/topoint[3]);
+ m_prevTargetPoint = topoint3;
+ m_prevSourcePoint = frompoint3;
+
+ /* 2. Get the object from PhysicsEnvironment */
+ /* Shoot! Beware that the first argument here is an
+ * ignore-object. We don't ignore anything... */
+
+ KX_IPhysicsController* physics_controller = cam->GetPhysicsController();
+ PHY_IPhysicsEnvironment* physics_environment = m_kxscene->GetPhysicsEnvironment();
+
+ bool result = false;
+
+ result = KX_RayCast::RayTest(physics_controller, physics_environment, frompoint3, topoint3, resultpoint, resultnormal, KX_RayCast::Callback<KX_MouseFocusSensor>(this));
+
+ result = (m_hitObject!=0);
+
+ return result;
+
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_MouseFocusSensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_MouseFocusSensor",
+ sizeof(KX_MouseFocusSensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_MouseFocusSensor::Parents[] = {
+ &KX_MouseFocusSensor::Type,
+ &SCA_MouseSensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_MouseFocusSensor::Methods[] = {
+ {"getRayTarget", (PyCFunction) KX_MouseFocusSensor::sPyGetRayTarget,
+ METH_VARARGS, GetRayTarget_doc},
+ {"getRaySource", (PyCFunction) KX_MouseFocusSensor::sPyGetRaySource,
+ METH_VARARGS, GetRaySource_doc},
+ {"getHitObject",(PyCFunction) KX_MouseFocusSensor::sPyGetHitObject,METH_VARARGS, GetHitObject_doc},
+ {"getHitPosition",(PyCFunction) KX_MouseFocusSensor::sPyGetHitPosition,METH_VARARGS, GetHitPosition_doc},
+ {"getHitNormal",(PyCFunction) KX_MouseFocusSensor::sPyGetHitNormal,METH_VARARGS, GetHitNormal_doc},
+ {"getRayDirection",(PyCFunction) KX_MouseFocusSensor::sPyGetRayDirection,METH_VARARGS, GetRayDirection_doc},
+
+
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* KX_MouseFocusSensor::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_MouseSensor);
+}
+
+
+char KX_MouseFocusSensor::GetHitObject_doc[] =
+"getHitObject()\n"
+"\tReturns the name of the object that was hit by this ray.\n";
+PyObject* KX_MouseFocusSensor::PyGetHitObject(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ if (m_hitObject)
+ {
+ return m_hitObject->AddRef();
+ }
+ Py_Return;
+}
+
+
+char KX_MouseFocusSensor::GetHitPosition_doc[] =
+"getHitPosition()\n"
+"\tReturns the position (in worldcoordinates) where the object was hit by this ray.\n";
+PyObject* KX_MouseFocusSensor::PyGetHitPosition(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ MT_Point3 pos = m_hitPosition;
+
+ PyObject* resultlist = PyList_New(3);
+ int index;
+ for (index=0;index<3;index++)
+ {
+ PyList_SetItem(resultlist,index,PyFloat_FromDouble(pos[index]));
+ }
+ return resultlist;
+
+}
+
+char KX_MouseFocusSensor::GetRayDirection_doc[] =
+"getRayDirection()\n"
+"\tReturns the direction from the ray (in worldcoordinates) .\n";
+PyObject* KX_MouseFocusSensor::PyGetRayDirection(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ MT_Vector3 dir = m_prevTargetPoint - m_prevSourcePoint;
+ dir.normalize();
+
+ PyObject* resultlist = PyList_New(3);
+ int index;
+ for (index=0;index<3;index++)
+ {
+ PyList_SetItem(resultlist,index,PyFloat_FromDouble(dir[index]));
+ }
+ return resultlist;
+
+}
+
+char KX_MouseFocusSensor::GetHitNormal_doc[] =
+"getHitNormal()\n"
+"\tReturns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray.\n";
+PyObject* KX_MouseFocusSensor::PyGetHitNormal(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ MT_Vector3 pos = m_hitNormal;
+
+ PyObject* resultlist = PyList_New(3);
+ int index;
+ for (index=0;index<3;index++)
+ {
+ PyList_SetItem(resultlist,index,PyFloat_FromDouble(pos[index]));
+ }
+ return resultlist;
+
+}
+
+
+/* getRayTarget */
+char KX_MouseFocusSensor::GetRayTarget_doc[] =
+"getRayTarget()\n"
+"\tReturns the target of the ray that seeks the focus object,\n"
+"\tin worldcoordinates.";
+PyObject* KX_MouseFocusSensor::PyGetRayTarget(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_prevTargetPoint[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_prevTargetPoint[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_prevTargetPoint[2]));
+
+ return retVal;
+}
+
+/* getRayTarget */
+char KX_MouseFocusSensor::GetRaySource_doc[] =
+"getRaySource()\n"
+"\tReturns the source of the ray that seeks the focus object,\n"
+"\tin worldcoordinates.";
+PyObject* KX_MouseFocusSensor::PyGetRaySource(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_prevSourcePoint[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_prevSourcePoint[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_prevSourcePoint[2]));
+
+ return retVal;
+}
+
+/* eof */
+
diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h
new file mode 100644
index 00000000000..cf7af709c48
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.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): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * KX_MouseFocusSensor determines mouse in/out/over events.
+ */
+
+#ifndef __KX_MOUSEFOCUSSENSOR
+#define __KX_MOUSEFOCUSSENSOR
+
+#include "SCA_MouseSensor.h"
+
+/**
+ * The mouse focus sensor extends the basic SCA_MouseSensor. It has
+ * been placed in KX because it needs access to the rasterizer and
+ * SuMO.
+ *
+ * - extend the valid modes?
+ * - */
+class KX_MouseFocusSensor : public SCA_MouseSensor
+{
+
+ Py_Header;
+
+ public:
+
+ KX_MouseFocusSensor(class SCA_MouseManager* keybdmgr,
+ int startx,
+ int starty,
+ short int mousemode,
+ int focusmode,
+ RAS_ICanvas* canvas,
+ KX_Scene* kxscene,
+ SCA_IObject* gameobj,
+ PyTypeObject* T=&Type );
+
+ virtual ~KX_MouseFocusSensor() { ; };
+ virtual CValue* GetReplica() {
+ CValue* replica = new KX_MouseFocusSensor(*this);
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+ };
+ /**
+ * @attention Overrides default evaluate.
+ */
+ virtual bool Evaluate(CValue* event);
+
+ virtual bool IsPositiveTrigger() {
+ bool result = m_positive_event;
+ if (m_invert) result = !result;
+ return result;
+ };
+
+ bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data);
+
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetRayTarget);
+ KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetRaySource);
+
+ KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetHitObject);
+ KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetHitPosition);
+ KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetHitNormal);
+ KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetRayDirection);
+
+ /* --------------------------------------------------------------------- */
+ SCA_IObject* m_hitObject;
+
+ private:
+ /**
+ * The focus mode. 1 for handling focus, 0 for not handling, 2 for focus on any object
+ */
+ int m_focusmode;
+
+ /**
+ * Flags whether the previous test showed a mouse-over.
+ */
+ bool m_mouse_over_in_previous_frame;
+
+ /**
+ * Flags whether the previous test evaluated positive.
+ */
+ bool m_positive_event;
+
+
+ /**
+ * Tests whether the object is in mouse focus in this frame.
+ */
+ bool ParentObjectHasFocus(void);
+
+ /**
+ * (in game world coordinates) the place where the object was hit.
+ */
+ MT_Point3 m_hitPosition;
+
+ /**
+ * (in game world coordinates) the position to which to shoot the ray.
+ */
+ MT_Point3 m_prevTargetPoint;
+
+ /**
+ * (in game world coordinates) the position from which to shoot the ray.
+ */
+ MT_Point3 m_prevSourcePoint;
+
+ /**
+ * (in game world coordinates) the face normal of the vertex where
+ * the object was hit. */
+ MT_Vector3 m_hitNormal;
+
+
+ /**
+ * Ref to the engine, for retrieving a reference to the current
+ * scene. */
+ class KX_KetsjiEngine* m_engine;
+
+
+ /**
+ * The active canvas. The size of this canvas determines a part of
+ * the start position of the picking ray. */
+ RAS_ICanvas* m_gp_canvas;
+
+ /**
+ * The KX scene that holds the camera. The camera position
+ * determines a part of the start location of the picking ray. */
+ KX_Scene* m_kxscene;
+
+};
+
+#endif //__KX_MOUSESENSOR
+
diff --git a/source/gameengine/Ketsji/KX_NearSensor.cpp b/source/gameengine/Ketsji/KX_NearSensor.cpp
new file mode 100644
index 00000000000..34561045cab
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_NearSensor.cpp
@@ -0,0 +1,283 @@
+/**
+ * Sense if other objects are near
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_NearSensor.h"
+#include "SCA_LogicManager.h"
+#include "KX_GameObject.h"
+#include "KX_TouchEventManager.h"
+#include "KX_Scene.h" // needed to create a replica
+#include "PHY_IPhysicsEnvironment.h"
+#include "PHY_IPhysicsController.h"
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+KX_NearSensor::KX_NearSensor(SCA_EventManager* eventmgr,
+ KX_GameObject* gameobj,
+ double margin,
+ double resetmargin,
+ bool bFindMaterial,
+ const STR_String& touchedpropname,
+ class KX_Scene* scene,
+ PHY_IPhysicsController* ctrl,
+ PyTypeObject* T)
+ :KX_TouchSensor(eventmgr,
+ gameobj,
+ bFindMaterial,
+ touchedpropname,
+ /* scene, */
+ T),
+ m_Margin(margin),
+ m_ResetMargin(resetmargin)
+
+{
+
+ gameobj->getClientInfo()->m_sensors.remove(this);
+ m_client_info = new KX_ClientObjectInfo(gameobj, KX_ClientObjectInfo::NEAR);
+ m_client_info->m_sensors.push_back(this);
+
+ //DT_ShapeHandle shape = (DT_ShapeHandle) vshape;
+ m_physCtrl = ctrl;
+ if (m_physCtrl)
+ {
+ m_physCtrl->SetMargin(m_Margin);
+ m_physCtrl->setNewClientInfo(m_client_info);
+ }
+ SynchronizeTransform();
+}
+
+void KX_NearSensor::RegisterSumo(KX_TouchEventManager *touchman)
+{
+ if (m_physCtrl)
+ {
+ touchman->GetPhysicsEnvironment()->addSensor(m_physCtrl);
+ }
+}
+
+CValue* KX_NearSensor::GetReplica()
+{
+ KX_NearSensor* replica = new KX_NearSensor(*this);
+ replica->m_colliders = new CListValue();
+ replica->m_bCollision = false;
+ replica->m_bTriggered= false;
+ replica->m_hitObject = NULL;
+ replica->m_bLastTriggered = false;
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ replica->m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::NEAR);
+
+ if (replica->m_physCtrl)
+ {
+ replica->m_physCtrl = replica->m_physCtrl->GetReplica();
+ if (replica->m_physCtrl)
+ {
+ //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->addSensor(replica->m_physCtrl);
+ replica->m_physCtrl->SetMargin(m_Margin);
+ replica->m_physCtrl->setNewClientInfo(replica->m_client_info);
+ }
+
+ }
+ //static_cast<KX_TouchEventManager*>(m_eventmgr)->RegisterSensor(this);
+ //todo: make sure replication works fine
+ //>m_sumoObj = new SM_Object(DT_NewSphere(0.0),NULL,NULL,NULL);
+ //replica->m_sumoObj->setMargin(m_Margin);
+ //replica->m_sumoObj->setClientObject(replica->m_client_info);
+
+ ((KX_GameObject*)replica->GetParent())->GetSGNode()->ComputeWorldTransforms(NULL);
+ replica->SynchronizeTransform();
+
+ return replica;
+}
+
+
+
+void KX_NearSensor::ReParent(SCA_IObject* parent)
+{
+
+ SCA_ISensor::ReParent(parent);
+
+ m_client_info->m_gameobject = static_cast<KX_GameObject*>(parent);
+ m_client_info->m_sensors.push_back(this);
+
+
+/* KX_ClientObjectInfo *client_info = gameobj->getClientInfo();
+ client_info->m_gameobject = gameobj;
+ client_info->m_auxilary_info = NULL;
+
+ client_info->m_sensors.push_back(this);
+ SCA_ISensor::ReParent(parent);
+*/
+ ((KX_GameObject*)GetParent())->GetSGNode()->ComputeWorldTransforms(NULL);
+ SynchronizeTransform();
+}
+
+
+
+KX_NearSensor::~KX_NearSensor()
+{
+ // for nearsensor, the sensor is the 'owner' of sumoobj
+ // for touchsensor, it's the parent
+ if (m_physCtrl)
+ {
+ //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->removeSensor(m_physCtrl);
+ delete m_physCtrl;
+ m_physCtrl = NULL;
+ }
+
+
+ if (m_client_info)
+ delete m_client_info;
+}
+
+
+bool KX_NearSensor::Evaluate(CValue* event)
+{
+ bool result = false;
+// KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
+
+ if (m_bTriggered != m_bLastTriggered)
+ {
+ m_bLastTriggered = m_bTriggered;
+ if (m_bTriggered)
+ {
+ if (m_physCtrl)
+ {
+ m_physCtrl->SetMargin(m_ResetMargin);
+ }
+ } else
+ {
+ if (m_physCtrl)
+ {
+ m_physCtrl->SetMargin(m_Margin);
+ }
+
+ }
+ result = true;
+ }
+
+ return result;
+}
+
+
+
+bool KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData * coll_data)
+{
+// KX_TouchEventManager* toucheventmgr = static_cast<KX_TouchEventManager*>(m_eventmgr);
+ KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
+
+ // need the mapping from PHY_IPhysicsController to gameobjects now
+
+ KX_ClientObjectInfo* client_info =static_cast<KX_ClientObjectInfo*> (obj1 == m_physCtrl?
+ ((PHY_IPhysicsController*)obj2)->getNewClientInfo() :
+ ((PHY_IPhysicsController*)obj1)->getNewClientInfo());
+
+ KX_GameObject* gameobj = ( client_info ?
+ client_info->m_gameobject :
+ NULL);
+
+ if (gameobj && (gameobj != parent))
+ {
+ if (!m_colliders->SearchValue(gameobj))
+ m_colliders->Add(gameobj->AddRef());
+ // only take valid colliders
+ if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
+ {
+ if ((m_touchedpropname.Length() == 0) ||
+ (gameobj->GetProperty(m_touchedpropname)))
+ {
+ m_bTriggered = true;
+ m_hitObject = gameobj;
+ }
+ }
+ }
+
+ return DT_CONTINUE;
+}
+
+
+
+// python embedding
+PyTypeObject KX_NearSensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_NearSensor",
+ sizeof(KX_NearSensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+
+PyParentObject KX_NearSensor::Parents[] = {
+ &KX_NearSensor::Type,
+ &KX_TouchSensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+PyMethodDef KX_NearSensor::Methods[] = {
+ {"setProperty",
+ (PyCFunction) KX_NearSensor::sPySetProperty, METH_VARARGS, SetProperty_doc},
+ {"getProperty",
+ (PyCFunction) KX_NearSensor::sPyGetProperty, METH_VARARGS, GetProperty_doc},
+ {"getHitObject",
+ (PyCFunction) KX_NearSensor::sPyGetHitObject, METH_VARARGS, GetHitObject_doc},
+ {"getHitObjectList",
+ (PyCFunction) KX_NearSensor::sPyGetHitObjectList, METH_VARARGS, GetHitObjectList_doc},
+ {NULL,NULL} //Sentinel
+};
+
+
+PyObject*
+KX_NearSensor::_getattr(const STR_String& attr)
+{
+ _getattr_up(KX_TouchSensor);
+}
+
diff --git a/source/gameengine/Ketsji/KX_NearSensor.h b/source/gameengine/Ketsji/KX_NearSensor.h
new file mode 100644
index 00000000000..d1b8984b91b
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_NearSensor.h
@@ -0,0 +1,87 @@
+/**
+ * Sense if other objects are near
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 KX_NEARSENSOR_H
+#define KX_NEARSENSOR_H
+
+#include "KX_TouchSensor.h"
+#include "KX_ClientObjectInfo.h"
+
+class KX_Scene;
+struct PHY_CollData;
+
+class KX_NearSensor : public KX_TouchSensor
+{
+ Py_Header;
+protected:
+ double m_Margin;
+ double m_ResetMargin;
+ KX_Scene* m_scene;
+ KX_ClientObjectInfo* m_client_info;
+public:
+ KX_NearSensor(class SCA_EventManager* eventmgr,
+ class KX_GameObject* gameobj,
+ double margin,
+ double resetmargin,
+ bool bFindMaterial,
+ const STR_String& touchedpropname,
+ class KX_Scene* scene,
+ PHY_IPhysicsController* ctrl,
+ PyTypeObject* T=&Type);
+/*
+public:
+ KX_NearSensor(class SCA_EventManager* eventmgr,
+ class KX_GameObject* gameobj,
+ double margin,
+ double resetmargin,
+ bool bFindMaterial,
+ const STR_String& touchedpropname,
+ class KX_Scene* scene,
+ PyTypeObject* T=&Type);
+*/
+ virtual ~KX_NearSensor();
+ virtual CValue* GetReplica();
+ virtual bool Evaluate(CValue* event);
+
+ virtual void ReParent(SCA_IObject* parent);
+ virtual bool NewHandleCollision(void* obj1,void* obj2,
+ const PHY_CollData * coll_data);
+ virtual void RegisterSumo(KX_TouchEventManager *touchman);
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+};
+
+#endif //KX_NEARSENSOR_H
+
diff --git a/source/gameengine/Ketsji/KX_ObColorIpoSGController.cpp b/source/gameengine/Ketsji/KX_ObColorIpoSGController.cpp
new file mode 100644
index 00000000000..b6d385da8ca
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ObColorIpoSGController.cpp
@@ -0,0 +1,116 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_ObColorIpoSGController.h"
+#include "KX_ScalarInterpolator.h"
+#include "KX_GameObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(_WIN64)
+typedef unsigned __int64 uint_ptr;
+#else
+typedef unsigned long uint_ptr;
+#endif
+
+
+bool KX_ObColorIpoSGController::Update(double currentTime)
+{
+ if (m_modified)
+ {
+ m_rgba[0]=0;
+ m_rgba[1]=0;
+ m_rgba[2]=0;
+ m_rgba[3]=0;
+
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ (*i)->Execute(m_ipotime);
+ }
+
+
+ SG_Spatial* ob = (SG_Spatial*)m_pObject;
+ KX_GameObject* kxgameobj= (KX_GameObject*) ob->GetSGClientObject();
+
+ kxgameobj->SetObjectColor(m_rgba);
+
+
+ m_modified=false;
+ }
+ return false;
+}
+
+
+void KX_ObColorIpoSGController::AddInterpolator(KX_IInterpolator* interp)
+{
+ this->m_interpolators.push_back(interp);
+}
+
+SG_Controller* KX_ObColorIpoSGController::GetReplica(class SG_Node* destnode)
+{
+ KX_ObColorIpoSGController* iporeplica = new KX_ObColorIpoSGController(*this);
+ // clear object that ipo acts on
+ iporeplica->ClearObject();
+
+ // dirty hack, ask Gino for a better solution in the ipo implementation
+ // hacken en zagen, in what we call datahiding, not written for replication :(
+
+ T_InterpolatorList oldlist = m_interpolators;
+ iporeplica->m_interpolators.clear();
+
+ T_InterpolatorList::iterator i;
+ for (i = oldlist.begin(); !(i == oldlist.end()); ++i) {
+ KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i));
+ iporeplica->AddInterpolator(copyipo);
+
+ MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget();
+ uint_ptr orgbase = (uint_ptr)this;
+ uint_ptr orgloc = (uint_ptr)scaal;
+ uint_ptr offset = orgloc-orgbase;
+ uint_ptr newaddrbase = (uint_ptr)iporeplica + offset;
+ MT_Scalar* blaptr = (MT_Scalar*) newaddrbase;
+ copyipo->SetNewTarget((MT_Scalar*)blaptr);
+ }
+
+ return iporeplica;
+}
+
+KX_ObColorIpoSGController::~KX_ObColorIpoSGController()
+{
+
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ delete (*i);
+ }
+
+}
diff --git a/source/gameengine/Ketsji/KX_ObColorIpoSGController.h b/source/gameengine/Ketsji/KX_ObColorIpoSGController.h
new file mode 100644
index 00000000000..02a58ffd95a
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ObColorIpoSGController.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 KX_OBCOLORIPOSGCONTROLLER_H
+#define KX_OBCOLORIPOSGCONTROLLER_H
+
+#include "SG_Controller.h"
+#include "SG_Spatial.h"
+#include "KX_IInterpolator.h"
+
+class KX_ObColorIpoSGController : public SG_Controller
+{
+public:
+ MT_Vector4 m_rgba;
+
+
+private:
+ T_InterpolatorList m_interpolators;
+ bool m_modified;
+
+ double m_ipotime;
+public:
+ KX_ObColorIpoSGController() :
+ m_modified(true),
+ m_ipotime(0.0)
+ {}
+ virtual ~KX_ObColorIpoSGController();
+ virtual SG_Controller* GetReplica(class SG_Node* destnode);
+ virtual bool Update(double time);
+ virtual void SetSimulatedTime(double time) {
+ m_ipotime = time;
+ m_modified = true;
+ }
+
+ void
+ SetOption(
+ int option,
+ int value
+ ){
+ // intentionally empty
+ };
+
+
+ void AddInterpolator(KX_IInterpolator* interp);
+};
+
+#endif // KX_OBCOLORIPOSGCONTROLLER_H
+
diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
new file mode 100644
index 00000000000..74f3dd1ef3b
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
@@ -0,0 +1,398 @@
+/**
+ * Do translation/rotation actions
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_ObjectActuator.h"
+#include "KX_GameObject.h"
+#include "KX_IPhysicsController.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+KX_ObjectActuator::
+KX_ObjectActuator(
+ SCA_IObject* gameobj,
+ const MT_Vector3& force,
+ const MT_Vector3& torque,
+ const MT_Vector3& dloc,
+ const MT_Vector3& drot,
+ const MT_Vector3& linV,
+ const MT_Vector3& angV,
+ const KX_LocalFlags& flag,
+ PyTypeObject* T
+) :
+ SCA_IActuator(gameobj,T),
+ m_force(force),
+ m_torque(torque),
+ m_dloc(dloc),
+ m_drot(drot),
+ m_linear_velocity(linV),
+ m_angular_velocity(angV),
+ m_bitLocalFlag (flag),
+ m_active_combined_velocity (false)
+{
+}
+
+bool KX_ObjectActuator::Update()
+{
+
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ KX_GameObject *parent = static_cast<KX_GameObject *>(GetParent());
+
+ if (bNegativeEvent) {
+ // If we previously set the linear velocity we now have to inform
+ // the physics controller that we no longer wish to apply it and that
+ // it should reconcile the externally set velocity with it's
+ // own velocity.
+ if (m_active_combined_velocity) {
+ parent->ResolveCombinedVelocities(
+ m_linear_velocity,
+ m_angular_velocity,
+ (m_bitLocalFlag.LinearVelocity) != 0,
+ (m_bitLocalFlag.AngularVelocity) != 0
+ );
+ m_active_combined_velocity = false;
+ }
+ return false;
+
+ } else
+ if (parent)
+ {
+ /* Probably better to use some flags, so these MT_zero tests can be */
+ /* skipped. */
+ if (!MT_fuzzyZero(m_force))
+ {
+ parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
+ }
+ if (!MT_fuzzyZero(m_torque))
+ {
+ parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0);
+ }
+ if (!MT_fuzzyZero(m_dloc))
+ {
+ parent->ApplyMovement(m_dloc,(m_bitLocalFlag.DLoc) != 0);
+ }
+ if (!MT_fuzzyZero(m_drot))
+ {
+ parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0);
+ }
+ if (!MT_fuzzyZero(m_linear_velocity))
+ {
+ if (m_bitLocalFlag.AddOrSetLinV) {
+ parent->addLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
+ } else {
+ m_active_combined_velocity = true;
+ parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
+ }
+ }
+ if (!MT_fuzzyZero(m_angular_velocity))
+ {
+ parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0);
+ m_active_combined_velocity = true;
+ }
+
+ }
+ return true;
+}
+
+
+
+CValue* KX_ObjectActuator::GetReplica()
+{
+ KX_ObjectActuator* replica = new KX_ObjectActuator(*this);//m_float,GetName());
+ replica->ProcessReplica();
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+/* some 'standard' utilities... */
+bool KX_ObjectActuator::isValid(KX_ObjectActuator::KX_OBJECT_ACT_VEC_TYPE type)
+{
+ bool res = false;
+ res = (type > KX_OBJECT_ACT_NODEF) && (type < KX_OBJECT_ACT_MAX);
+ return res;
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_ObjectActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_ObjectActuator",
+ sizeof(KX_ObjectActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_ObjectActuator::Parents[] = {
+ &KX_ObjectActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_ObjectActuator::Methods[] = {
+ {"getForce", (PyCFunction) KX_ObjectActuator::sPyGetForce, METH_VARARGS},
+ {"setForce", (PyCFunction) KX_ObjectActuator::sPySetForce, METH_VARARGS},
+ {"getTorque", (PyCFunction) KX_ObjectActuator::sPyGetTorque, METH_VARARGS},
+ {"setTorque", (PyCFunction) KX_ObjectActuator::sPySetTorque, METH_VARARGS},
+ {"getDLoc", (PyCFunction) KX_ObjectActuator::sPyGetDLoc, METH_VARARGS},
+ {"setDLoc", (PyCFunction) KX_ObjectActuator::sPySetDLoc, METH_VARARGS},
+ {"getDRot", (PyCFunction) KX_ObjectActuator::sPyGetDRot, METH_VARARGS},
+ {"setDRot", (PyCFunction) KX_ObjectActuator::sPySetDRot, METH_VARARGS},
+ {"getLinearVelocity", (PyCFunction) KX_ObjectActuator::sPyGetLinearVelocity, METH_VARARGS},
+ {"setLinearVelocity", (PyCFunction) KX_ObjectActuator::sPySetLinearVelocity, METH_VARARGS},
+ {"getAngularVelocity", (PyCFunction) KX_ObjectActuator::sPyGetAngularVelocity, METH_VARARGS},
+ {"setAngularVelocity", (PyCFunction) KX_ObjectActuator::sPySetAngularVelocity, METH_VARARGS},
+
+
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* KX_ObjectActuator::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IActuator);
+};
+
+/* 1. set ------------------------------------------------------------------ */
+/* Removed! */
+
+/* 2. getForce */
+PyObject* KX_ObjectActuator::PyGetForce(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject *retVal = PyList_New(4);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_force[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_force[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_force[2]));
+ PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.Force));
+
+ return retVal;
+}
+/* 3. setForce */
+PyObject* KX_ObjectActuator::PySetForce(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[3];
+ int bToggle = 0;
+ if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
+ &vecArg[2], &bToggle)) {
+ return NULL;
+ }
+ m_force.setValue(vecArg);
+ m_bitLocalFlag.Force = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+/* 4. getTorque */
+PyObject* KX_ObjectActuator::PyGetTorque(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject *retVal = PyList_New(4);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_torque[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_torque[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_torque[2]));
+ PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.Torque));
+
+ return retVal;
+}
+/* 5. setTorque */
+PyObject* KX_ObjectActuator::PySetTorque(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[3];
+ int bToggle = 0;
+ if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
+ &vecArg[2], &bToggle)) {
+ return NULL;
+ }
+ m_torque.setValue(vecArg);
+ m_bitLocalFlag.Torque = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+/* 6. getDLoc */
+PyObject* KX_ObjectActuator::PyGetDLoc(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject *retVal = PyList_New(4);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_dloc[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_dloc[2]));
+ PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.DLoc));
+
+ return retVal;
+}
+/* 7. setDLoc */
+PyObject* KX_ObjectActuator::PySetDLoc(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[3];
+ int bToggle = 0;
+ if(!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
+ &vecArg[2], &bToggle)) {
+ return NULL;
+ }
+ m_dloc.setValue(vecArg);
+ m_bitLocalFlag.DLoc = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+/* 8. getDRot */
+PyObject* KX_ObjectActuator::PyGetDRot(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject *retVal = PyList_New(4);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_drot[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_drot[2]));
+ PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.DRot));
+
+ return retVal;
+}
+/* 9. setDRot */
+PyObject* KX_ObjectActuator::PySetDRot(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[3];
+ int bToggle = 0;
+ if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
+ &vecArg[2], &bToggle)) {
+ return NULL;
+ }
+ m_drot.setValue(vecArg);
+ m_bitLocalFlag.DRot = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+/* 10. getLinearVelocity */
+PyObject* KX_ObjectActuator::PyGetLinearVelocity(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *retVal = PyList_New(4);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2]));
+ PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.LinearVelocity));
+
+ return retVal;
+}
+
+/* 11. setLinearVelocity */
+PyObject* KX_ObjectActuator::PySetLinearVelocity(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float vecArg[3];
+ int bToggle = 0;
+ if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
+ &vecArg[2], &bToggle)) {
+ return NULL;
+ }
+ m_linear_velocity.setValue(vecArg);
+ m_bitLocalFlag.LinearVelocity = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+
+/* 12. getAngularVelocity */
+PyObject* KX_ObjectActuator::PyGetAngularVelocity(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *retVal = PyList_New(4);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_angular_velocity[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_angular_velocity[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_angular_velocity[2]));
+ PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.AngularVelocity));
+
+ return retVal;
+}
+/* 13. setAngularVelocity */
+PyObject* KX_ObjectActuator::PySetAngularVelocity(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float vecArg[3];
+ int bToggle = 0;
+ if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
+ &vecArg[2], &bToggle)) {
+ return NULL;
+ }
+ m_angular_velocity.setValue(vecArg);
+ m_bitLocalFlag.AngularVelocity = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+
+
+
+/* eof */
diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.h b/source/gameengine/Ketsji/KX_ObjectActuator.h
new file mode 100644
index 00000000000..1ef3e34625a
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ObjectActuator.h
@@ -0,0 +1,141 @@
+/**
+ * Do translation/rotation actions
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_OBJECTACTUATOR
+#define __KX_OBJECTACTUATOR
+
+#include "SCA_IActuator.h"
+#include "MT_Vector3.h"
+
+//
+// Bitfield that stores the flags for each CValue derived class
+//
+struct KX_LocalFlags {
+ KX_LocalFlags() :
+ Force(false),
+ Torque(false),
+ DRot(false),
+ DLoc(false),
+ LinearVelocity(false),
+ AngularVelocity(false),
+ AddOrSetLinV(false)
+ {
+ }
+
+ unsigned short Force : 1;
+ unsigned short Torque : 1;
+ unsigned short DRot : 1;
+ unsigned short DLoc : 1;
+ unsigned short LinearVelocity : 1;
+ unsigned short AngularVelocity : 1;
+ unsigned short AddOrSetLinV : 1;
+};
+
+class KX_ObjectActuator : public SCA_IActuator
+{
+ Py_Header;
+
+ MT_Vector3 m_force;
+ MT_Vector3 m_torque;
+ MT_Vector3 m_dloc;
+ MT_Vector3 m_drot;
+ MT_Vector3 m_linear_velocity;
+ MT_Vector3 m_angular_velocity;
+ KX_LocalFlags m_bitLocalFlag;
+
+ // A hack bool -- oh no sorry everyone
+ // This bool is used to check if we have informed
+ // the physics object that we are no longer
+ // setting linear velocity.
+
+ bool m_active_combined_velocity;
+
+public:
+ enum KX_OBJECT_ACT_VEC_TYPE {
+ KX_OBJECT_ACT_NODEF = 0,
+ KX_OBJECT_ACT_FORCE,
+ KX_OBJECT_ACT_TORQUE,
+ KX_OBJECT_ACT_DLOC,
+ KX_OBJECT_ACT_DROT,
+ KX_OBJECT_ACT_LINEAR_VELOCITY,
+ KX_OBJECT_ACT_ANGULAR_VELOCITY,
+ KX_OBJECT_ACT_MAX
+ };
+
+ /**
+ * Check whether this is a valid vector mode
+ */
+ bool isValid(KX_OBJECT_ACT_VEC_TYPE type);
+
+ KX_ObjectActuator(
+ SCA_IObject* gameobj,
+ const MT_Vector3& force,
+ const MT_Vector3& torque,
+ const MT_Vector3& dloc,
+ const MT_Vector3& drot,
+ const MT_Vector3& linV,
+ const MT_Vector3& angV,
+ const KX_LocalFlags& flag,
+ PyTypeObject* T=&Type
+ );
+
+ CValue* GetReplica();
+
+ void SetForceLoc(const double force[3]) { /*m_force=force;*/ }
+ virtual bool Update();
+
+
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ KX_PYMETHOD(KX_ObjectActuator,GetForce);
+ KX_PYMETHOD(KX_ObjectActuator,SetForce);
+ KX_PYMETHOD(KX_ObjectActuator,GetTorque);
+ KX_PYMETHOD(KX_ObjectActuator,SetTorque);
+ KX_PYMETHOD(KX_ObjectActuator,GetDLoc);
+ KX_PYMETHOD(KX_ObjectActuator,SetDLoc);
+ KX_PYMETHOD(KX_ObjectActuator,GetDRot);
+ KX_PYMETHOD(KX_ObjectActuator,SetDRot);
+ KX_PYMETHOD(KX_ObjectActuator,GetLinearVelocity);
+ KX_PYMETHOD(KX_ObjectActuator,SetLinearVelocity);
+ KX_PYMETHOD(KX_ObjectActuator,GetAngularVelocity);
+ KX_PYMETHOD(KX_ObjectActuator,SetAngularVelocity);
+};
+
+#endif //__KX_OBJECTACTUATOR
+
diff --git a/source/gameengine/Ketsji/KX_OdePhysicsController.cpp b/source/gameengine/Ketsji/KX_OdePhysicsController.cpp
new file mode 100644
index 00000000000..58c04d34149
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_OdePhysicsController.cpp
@@ -0,0 +1,251 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * The contents of this file may be used under the terms of either the GNU
+ * General Public License Version 2 or later (the "GPL", see
+ * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or
+ * later (the "BL", see http://www.blender.org/BL/ ) which has to be
+ * bought from the Blender Foundation to become active, in which case the
+ * above mentioned GPL option does not apply.
+ *
+ * The Original Code is Copyright (C) 2002 by 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 "KX_ConvertPhysicsObject.h"
+
+#ifdef USE_ODE
+
+#include "KX_OdePhysicsController.h"
+#include "KX_GameObject.h"
+#include "KX_MotionState.h"
+
+#include "MT_assert.h"
+
+#include "PHY_IPhysicsEnvironment.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_OdePhysicsController::KX_OdePhysicsController(
+ bool dyna,
+ bool fullRigidBody,
+ bool phantom,
+ class PHY_IMotionState* motionstate,
+ struct dxSpace* space,
+ struct dxWorld* world,
+ float mass,
+ float friction,
+ float restitution,
+ bool implicitsphere,
+ float center[3],
+ float extends[3],
+ float radius
+ )
+: KX_IPhysicsController(dyna,(PHY_IPhysicsController*)this),
+ODEPhysicsController(
+dyna,fullRigidBody,phantom,motionstate,
+space,world,mass,friction,restitution,
+implicitsphere,center,extends,radius)
+{
+};
+
+
+bool KX_OdePhysicsController::Update(double time)
+{
+ return SynchronizeMotionStates(time);
+}
+
+void KX_OdePhysicsController::SetObject (SG_IObject* object)
+{
+ SG_Controller::SetObject(object);
+
+ // cheating here...
+ KX_GameObject* gameobj = (KX_GameObject*) object->GetSGClientObject();
+ gameobj->SetPhysicsController(this);
+
+}
+
+
+
+void KX_OdePhysicsController::applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse)
+{
+ ODEPhysicsController::applyImpulse(attach[0],attach[1],attach[2],impulse[0],impulse[1],impulse[2]);
+}
+
+
+
+void KX_OdePhysicsController::RelativeTranslate(const MT_Vector3& dloc,bool local)
+{
+ ODEPhysicsController::RelativeTranslate(dloc[0],dloc[1],dloc[2],local);
+
+}
+void KX_OdePhysicsController::RelativeRotate(const MT_Matrix3x3& drot,bool local)
+{
+ double oldmat[12];
+ drot.getValue(oldmat);
+ float newmat[9];
+ float *m = &newmat[0];
+ double *orgm = &oldmat[0];
+
+ *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++;
+ *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++;
+ *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++;
+
+ ODEPhysicsController::RelativeRotate(newmat,local);
+
+}
+
+void KX_OdePhysicsController::ApplyTorque(const MT_Vector3& torque,bool local)
+{
+ ODEPhysicsController::ApplyTorque(torque[0],torque[1],torque[2],local);
+
+}
+void KX_OdePhysicsController::ApplyForce(const MT_Vector3& force,bool local)
+{
+ ODEPhysicsController::ApplyForce(force[0],force[1],force[2],local);
+
+}
+MT_Vector3 KX_OdePhysicsController::GetLinearVelocity()
+{
+ return MT_Vector3(0,0,0);
+}
+
+MT_Vector3 KX_OdePhysicsController::GetVelocity(const MT_Point3& pos)
+{
+ return MT_Vector3(0,0,0);
+}
+
+void KX_OdePhysicsController::SetAngularVelocity(const MT_Vector3& ang_vel,bool local)
+{
+
+}
+void KX_OdePhysicsController::SetLinearVelocity(const MT_Vector3& lin_vel,bool local)
+{
+ ODEPhysicsController::SetLinearVelocity(lin_vel[0],lin_vel[1],lin_vel[2],local);
+}
+
+void KX_OdePhysicsController::setOrientation(const MT_Quaternion& orn)
+{
+ ODEPhysicsController::setOrientation(orn[0],orn[1],orn[2],orn[3]);
+}
+
+void KX_OdePhysicsController::getOrientation(MT_Quaternion& orn)
+{
+ float florn[4];
+ florn[0]=orn[0];
+ florn[1]=orn[1];
+ florn[2]=orn[2];
+ florn[3]=orn[3];
+ ODEPhysicsController::getOrientation(florn[0],florn[1],florn[2],florn[3]);
+ orn[0] = florn[0];
+ orn[1] = florn[1];
+ orn[2] = florn[2];
+ orn[3] = florn[3];
+
+
+}
+
+void KX_OdePhysicsController::setPosition(const MT_Point3& pos)
+{
+ ODEPhysicsController::setPosition(pos[0],pos[1],pos[2]);
+}
+
+void KX_OdePhysicsController::setScaling(const MT_Vector3& scaling)
+{
+}
+
+MT_Scalar KX_OdePhysicsController::GetMass()
+{
+ return ODEPhysicsController::getMass();
+}
+
+MT_Vector3 KX_OdePhysicsController::getReactionForce()
+{
+ return MT_Vector3(0,0,0);
+}
+void KX_OdePhysicsController::setRigidBody(bool rigid)
+{
+
+}
+
+void KX_OdePhysicsController::SuspendDynamics()
+{
+ ODEPhysicsController::SuspendDynamics();
+}
+void KX_OdePhysicsController::RestoreDynamics()
+{
+ ODEPhysicsController::RestoreDynamics();
+}
+
+
+SG_Controller* KX_OdePhysicsController::GetReplica(class SG_Node* destnode)
+{
+ PHY_IMotionState* motionstate = new KX_MotionState(destnode);
+ KX_OdePhysicsController* copyctrl = new KX_OdePhysicsController(*this);
+
+ // nlin: copied from KX_SumoPhysicsController.cpp. Not 100% sure what this does....
+ // furthermore, the parentctrl is not used in ODEPhysicsController::PostProcessReplica, but
+ // maybe it can/should be used in the future...
+
+ // begin copy block ------------------------------------------------------------------
+
+ //parentcontroller is here be able to avoid collisions between parent/child
+
+ PHY_IPhysicsController* parentctrl = NULL;
+
+ if (destnode != destnode->GetRootSGParent())
+ {
+ KX_GameObject* clientgameobj = (KX_GameObject*) destnode->GetRootSGParent()->GetSGClientObject();
+ if (clientgameobj)
+ {
+ parentctrl = (KX_OdePhysicsController*)clientgameobj->GetPhysicsController();
+ } else
+ {
+ // it could be a false node, try the children
+ NodeList::const_iterator childit;
+ for (
+ childit = destnode->GetSGChildren().begin();
+ childit!= destnode->GetSGChildren().end();
+ ++childit
+ ) {
+ KX_GameObject* clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject());
+ if (clientgameobj)
+ {
+ parentctrl = (KX_OdePhysicsController*)clientgameobj->GetPhysicsController();
+ }
+ }
+ }
+ }
+ // end copy block ------------------------------------------------------------------
+
+ copyctrl->PostProcessReplica(motionstate, this);
+
+ return copyctrl;
+
+}
+
+void KX_OdePhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ)
+{
+}
+
+
+void KX_OdePhysicsController::SetSumoTransform(bool nondynaonly)
+{
+
+}
+ // todo: remove next line !
+void KX_OdePhysicsController::SetSimulatedTime(double time)
+{
+
+}
+
+#endif //USE_ODE
diff --git a/source/gameengine/Ketsji/KX_OdePhysicsController.h b/source/gameengine/Ketsji/KX_OdePhysicsController.h
new file mode 100644
index 00000000000..f5bc7dee165
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_OdePhysicsController.h
@@ -0,0 +1,102 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * The contents of this file may be used under the terms of either the GNU
+ * General Public License Version 2 or later (the "GPL", see
+ * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or
+ * later (the "BL", see http://www.blender.org/BL/ ) which has to be
+ * bought from the Blender Foundation to become active, in which case the
+ * above mentioned GPL option does not apply.
+ *
+ * The Original Code is Copyright (C) 2002 by 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 __KX_ODEPHYSICSCONTROLLER_H
+#define __KX_ODEPHYSICSCONTROLLER_H
+
+#include "KX_IPhysicsController.h"
+#include "OdePhysicsController.h"
+
+/**
+ Physics Controller, a special kind of Scene Graph Transformation Controller.
+ It get's callbacks from Physics in case a transformation change took place.
+ Each time the scene graph get's updated, the controller get's a chance
+ in the 'Update' method to reflect changed.
+*/
+
+class KX_OdePhysicsController : public KX_IPhysicsController, public ODEPhysicsController
+
+{
+
+public:
+ KX_OdePhysicsController(
+ bool dyna,
+ bool fullRigidBody,
+ bool phantom,
+ class PHY_IMotionState* motionstate,
+ struct dxSpace* space,
+ struct dxWorld* world,
+ float mass,
+ float friction,
+ float restitution,
+ bool implicitsphere,
+ float center[3],
+ float extends[3],
+ float radius);
+
+ virtual ~KX_OdePhysicsController() {};
+
+ virtual void applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse);
+ virtual void SetObject (SG_IObject* object);
+
+ virtual void RelativeTranslate(const MT_Vector3& dloc,bool local);
+ virtual void RelativeRotate(const MT_Matrix3x3& drot,bool local);
+ virtual void ApplyTorque(const MT_Vector3& torque,bool local);
+ virtual void ApplyForce(const MT_Vector3& force,bool local);
+ virtual MT_Vector3 GetLinearVelocity();
+ virtual MT_Vector3 GetVelocity(const MT_Point3& pos);
+ virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local);
+ virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local);
+ virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ);
+ virtual void getOrientation(MT_Quaternion& orn);
+ virtual void setOrientation(const MT_Quaternion& orn);
+ virtual void setPosition(const MT_Point3& pos);
+ virtual void setScaling(const MT_Vector3& scaling);
+ virtual MT_Scalar GetMass();
+ virtual MT_Vector3 getReactionForce();
+ virtual void setRigidBody(bool rigid);
+
+ virtual void SuspendDynamics();
+ virtual void RestoreDynamics();
+
+
+ virtual SG_Controller* GetReplica(class SG_Node* destnode);
+
+
+ virtual void SetSumoTransform(bool nondynaonly);
+ // todo: remove next line !
+ virtual void SetSimulatedTime(double time);
+
+ // call from scene graph to update
+ virtual bool Update(double time);
+
+ void
+ SetOption(
+ int option,
+ int value
+ ){
+ // intentionally empty
+ };
+
+};
+
+#endif //__KX_ODEPHYSICSCONTROLLER_H
+
diff --git a/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp b/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp
new file mode 100644
index 00000000000..3d65e18a7d0
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp
@@ -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 "KX_OrientationInterpolator.h"
+#include "MT_Matrix3x3.h"
+#include "KX_IScalarInterpolator.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void KX_OrientationInterpolator::Execute(float currentTime) const {
+ MT_Vector3 eul(m_ipos[0]->GetValue(currentTime),
+ m_ipos[1]->GetValue(currentTime),
+ m_ipos[2]->GetValue(currentTime));
+ MT_Scalar ci = cos(eul[0]);
+ MT_Scalar cj = cos(eul[1]);
+ MT_Scalar ch = cos(eul[2]);
+ MT_Scalar si = sin(eul[0]);
+ MT_Scalar sj = sin(eul[1]);
+ MT_Scalar sh = sin(eul[2]);
+ MT_Scalar cc = ci*ch;
+ MT_Scalar cs = ci*sh;
+ MT_Scalar sc = si*ch;
+ MT_Scalar ss = si*sh;
+
+ m_target.setValue(cj*ch, sj*sc-cs, sj*cc+ss,
+ cj*sh, sj*ss+cc, sj*cs-sc,
+ -sj, cj*si, cj*ci);
+}
diff --git a/source/gameengine/Ketsji/KX_OrientationInterpolator.h b/source/gameengine/Ketsji/KX_OrientationInterpolator.h
new file mode 100644
index 00000000000..1fb91ef785d
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_OrientationInterpolator.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 KX_ORIENTATIONINTERPOLATOR
+#define KX_ORIENTATIONINTERPOLATOR
+
+#include "KX_IInterpolator.h"
+
+class MT_Matrix3x3;
+class KX_IScalarInterpolator;
+
+class KX_OrientationInterpolator : public KX_IInterpolator {
+public:
+ KX_OrientationInterpolator(MT_Matrix3x3& target,
+ KX_IScalarInterpolator **ipos)
+ : m_target(target)
+ {
+ m_ipos[0] = ipos[0];
+ m_ipos[1] = ipos[1];
+ m_ipos[2] = ipos[2];
+ }
+
+ virtual void Execute(float currentTime) const;
+
+private:
+ MT_Matrix3x3& m_target;
+ KX_IScalarInterpolator *m_ipos[3];
+};
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_PhysicsEngineEnums.h b/source/gameengine/Ketsji/KX_PhysicsEngineEnums.h
new file mode 100644
index 00000000000..bafc8620dfd
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PhysicsEngineEnums.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 __KX_PHYSICSENGINEENUMS
+#define __KX_PHYSICSENGINEENUMS
+
+enum e_PhysicsEngine
+{
+ NoSelection = -1,
+ UseNone = 0,
+ UseEnji = 1,
+ UseSumo = 2,
+ UseDynamo = 3,
+ UseODE = 4,
+ UseBullet = 5,
+};
+
+#endif //__KX_PHYSICSENGINEENUMS
+
diff --git a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp
new file mode 100644
index 00000000000..1bd5a0b3d42
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp
@@ -0,0 +1,167 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 <Python.h>
+#include "KX_PhysicsObjectWrapper.h"
+#include "PHY_IPhysicsEnvironment.h"
+#include "PHY_IPhysicsController.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_PhysicsObjectWrapper::KX_PhysicsObjectWrapper(
+ PHY_IPhysicsController* ctrl,
+ PHY_IPhysicsEnvironment* physenv,PyTypeObject *T) :
+ PyObjectPlus(T),
+ m_ctrl(ctrl),
+ m_physenv(physenv)
+{
+}
+
+KX_PhysicsObjectWrapper::~KX_PhysicsObjectWrapper()
+{
+}
+
+
+PyObject* KX_PhysicsObjectWrapper::PySetPosition(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float x,y,z;
+ if (PyArg_ParseTuple(args,"fff",&x,&y,&z))
+ {
+ m_ctrl->setPosition(x,y,z);
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+PyObject* KX_PhysicsObjectWrapper::PySetLinearVelocity(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float x,y,z;
+ int local;
+ if (PyArg_ParseTuple(args,"fffi",&x,&y,&z,&local))
+ {
+ m_ctrl->SetLinearVelocity(x,y,z,local != 0);
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+PyObject* KX_PhysicsObjectWrapper::PySetAngularVelocity(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float x,y,z;
+ int local;
+ if (PyArg_ParseTuple(args,"fffi",&x,&y,&z,&local))
+ {
+ m_ctrl->SetAngularVelocity(x,y,z,local != 0);
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+PyObject* KX_PhysicsObjectWrapper::PySetActive(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int active;
+ if (PyArg_ParseTuple(args,"i",&active))
+ {
+ m_ctrl->SetActive(active!=0);
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+
+
+//python specific stuff
+PyTypeObject KX_PhysicsObjectWrapper::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_PhysicsObjectWrapper",
+ sizeof(KX_PhysicsObjectWrapper),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_PhysicsObjectWrapper::Parents[] = {
+ &KX_PhysicsObjectWrapper::Type,
+ NULL
+};
+
+PyObject* KX_PhysicsObjectWrapper::_getattr(const STR_String& attr)
+{
+ _getattr_up(PyObjectPlus);
+}
+
+
+int KX_PhysicsObjectWrapper::_setattr(const STR_String& attr,PyObject* pyobj)
+{
+ PyTypeObject* type = pyobj->ob_type;
+ int result = 1;
+
+
+ if (type == &PyInt_Type)
+ {
+ result = 0;
+ }
+ if (type == &PyString_Type)
+ {
+ result = 0;
+ }
+ if (result)
+ result = PyObjectPlus::_setattr(attr,pyobj);
+
+ return result;
+};
+
+
+PyMethodDef KX_PhysicsObjectWrapper::Methods[] = {
+ {"setPosition",(PyCFunction) KX_PhysicsObjectWrapper::sPySetPosition, METH_VARARGS},
+ {"setLinearVelocity",(PyCFunction) KX_PhysicsObjectWrapper::sPySetLinearVelocity, METH_VARARGS},
+ {"setAngularVelocity",(PyCFunction) KX_PhysicsObjectWrapper::sPySetAngularVelocity, METH_VARARGS},
+ {"setActive",(PyCFunction) KX_PhysicsObjectWrapper::sPySetActive, METH_VARARGS},
+ {NULL,NULL} //Sentinel
+};
diff --git a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h
new file mode 100644
index 00000000000..3de94795b16
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.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 PHYP_PHYSICSOBJECT_WRAPPER
+#define PHYP_PHYSICSOBJECT_WRAPPER
+
+#include "Value.h"
+#include "PHY_DynamicTypes.h"
+
+class KX_PhysicsObjectWrapper : public PyObjectPlus
+{
+ Py_Header;
+
+ virtual PyObject* _getattr(const STR_String& attr);
+ virtual int _setattr(const STR_String& attr, PyObject *value);
+public:
+ KX_PhysicsObjectWrapper(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsEnvironment* physenv,PyTypeObject *T = &Type);
+ virtual ~KX_PhysicsObjectWrapper();
+
+ KX_PYMETHOD(KX_PhysicsObjectWrapper , SetPosition);
+ KX_PYMETHOD(KX_PhysicsObjectWrapper,SetLinearVelocity);
+ KX_PYMETHOD(KX_PhysicsObjectWrapper,SetAngularVelocity);
+ KX_PYMETHOD(KX_PhysicsObjectWrapper,SetActive);
+
+private:
+ class PHY_IPhysicsController* m_ctrl;
+ PHY_IPhysicsEnvironment* m_physenv;
+};
+
+#endif //PHYP_PHYSICSOBJECT_WRAPPER
+
diff --git a/source/gameengine/Ketsji/KX_PhysicsPropertiesobsolete.h b/source/gameengine/Ketsji/KX_PhysicsPropertiesobsolete.h
new file mode 100644
index 00000000000..09d9cffce98
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PhysicsPropertiesobsolete.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 KX_PROPSH
+#define KX_PROPSH
+
+#include <MT_Scalar.h>
+
+// Properties of dynamic objects
+struct KX_ShapeProps {
+ MT_Scalar m_mass; // Total mass
+ MT_Scalar m_inertia; // Inertia, should be a tensor some time
+ MT_Scalar m_lin_drag; // Linear drag (air, water) 0 = concrete, 1 = vacuum
+ MT_Scalar m_ang_drag; // Angular drag
+ MT_Scalar m_friction_scaling[3]; // Scaling for anisotropic friction. Component in range [0, 1]
+ bool m_do_anisotropic; // Should I do anisotropic friction?
+ bool m_do_fh; // Should the object have a linear Fh spring?
+ bool m_do_rot_fh; // Should the object have an angular Fh spring?
+};
+
+
+// Properties of collidable objects (non-ghost objects)
+struct KX_MaterialProps {
+ MT_Scalar m_restitution; // restitution of energie after a collision 0 = inelastic, 1 = elastic
+ MT_Scalar m_friction; // Coulomb friction (= ratio between the normal en maximum friction force)
+ MT_Scalar m_fh_spring; // Spring constant (both linear and angular)
+ MT_Scalar m_fh_damping; // Damping factor (linear and angular) in range [0, 1]
+ MT_Scalar m_fh_distance; // The range above the surface where Fh is active.
+ bool m_fh_normal; // Should the object slide off slopes?
+};
+
+#endif //KX_PROPSH
+
diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp
new file mode 100644
index 00000000000..5a15a0375dc
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp
@@ -0,0 +1,425 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_PolygonMaterial.h"
+
+#include "BKE_mesh.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+
+extern "C" {
+#include "BDR_drawmesh.h"
+}
+
+#include "DNA_material_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_image_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RAS_LightObject.h"
+#include "RAS_MaterialBucket.h"
+
+#include "KX_PyMath.h"
+
+KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname,
+ Material *material,
+ int tile,
+ int tilexrep,
+ int tileyrep,
+ int mode,
+ bool transparant,
+ bool zsort,
+ int lightlayer,
+ bool bIsTriangle,
+ void* clientobject,
+ struct MTFace* tface,
+ unsigned int* mcol,
+ PyTypeObject *T)
+ : PyObjectPlus(T),
+ RAS_IPolyMaterial(texname,
+ STR_String(material?material->id.name:""),
+ tile,
+ tilexrep,
+ tileyrep,
+ mode,
+ transparant,
+ zsort,
+ lightlayer,
+ bIsTriangle,
+ clientobject),
+ m_tface(tface),
+ m_mcol(mcol),
+ m_material(material),
+ m_pymaterial(0),
+ m_pass(0)
+{
+}
+
+KX_PolygonMaterial::~KX_PolygonMaterial()
+{
+ if (m_pymaterial)
+ {
+ Py_DECREF(m_pymaterial);
+ }
+}
+
+bool KX_PolygonMaterial::Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const
+{
+ bool dopass = false;
+ if (m_pymaterial)
+ {
+ PyObject *pyRasty = PyCObject_FromVoidPtr((void*)rasty, NULL); /* new reference */
+ PyObject *pyCachingInfo = PyCObject_FromVoidPtr((void*) &cachingInfo, NULL); /* new reference */
+
+ PyObject *ret = PyObject_CallMethod(m_pymaterial, "activate", "(NNO)", pyRasty, pyCachingInfo, (PyObject*) this);
+ if (ret)
+ {
+ bool value = PyInt_AsLong(ret);
+ Py_DECREF(ret);
+ dopass = value;
+ }
+ else
+ {
+ PyErr_Print();
+ }
+ }
+ else
+ {
+ switch (m_pass++)
+ {
+ case 0:
+ DefaultActivate(rasty, cachingInfo);
+ dopass = true;
+ break;
+ default:
+ m_pass = 0;
+ dopass = false;
+ break;
+ }
+ }
+
+ return dopass;
+}
+
+void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const
+{
+ if (GetCachingInfo() != cachingInfo)
+ {
+ if (!cachingInfo)
+ {
+ set_tpage(NULL);
+ }
+ cachingInfo = GetCachingInfo();
+
+ if ((m_drawingmode & 4)&& (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED))
+ {
+ update_realtime_texture((struct MTFace*) m_tface, rasty->GetTime());
+ set_tpage(m_tface);
+ rasty->EnableTextures(true);
+ }
+ else
+ {
+ set_tpage(NULL);
+ rasty->EnableTextures(false);
+ }
+
+ if(m_drawingmode & RAS_IRasterizer::KX_TWOSIDE)
+ {
+ rasty->SetCullFace(false);
+ }
+ else
+ {
+ rasty->SetCullFace(true);
+ }
+
+ if (m_drawingmode & RAS_IRasterizer::KX_LINES) {
+ rasty->SetLines(true);
+ }
+ else {
+ rasty->SetLines(false);
+ }
+ }
+
+ rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity);
+ rasty->SetShinyness(m_shininess);
+ rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0);
+ if (m_material)
+ rasty->SetPolygonOffset(-m_material->zoffs, 0.0);
+}
+
+//----------------------------------------------------------------------------
+//Python
+
+
+PyMethodDef KX_PolygonMaterial::Methods[] = {
+ KX_PYMETHODTABLE(KX_PolygonMaterial, setCustomMaterial),
+ KX_PYMETHODTABLE(KX_PolygonMaterial, updateTexture),
+ KX_PYMETHODTABLE(KX_PolygonMaterial, setTexture),
+ KX_PYMETHODTABLE(KX_PolygonMaterial, activate),
+// KX_PYMETHODTABLE(KX_PolygonMaterial, setPerPixelLights),
+
+ {NULL,NULL} //Sentinel
+};
+
+
+PyTypeObject KX_PolygonMaterial::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_PolygonMaterial",
+ sizeof(KX_PolygonMaterial),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0 //&cvalue_as_number,
+};
+
+PyParentObject KX_PolygonMaterial::Parents[] = {
+ &PyObjectPlus::Type,
+ &KX_PolygonMaterial::Type,
+ NULL
+};
+
+PyObject* KX_PolygonMaterial::_getattr(const STR_String& attr)
+{
+ if (attr == "texture")
+ return PyString_FromString(m_texturename.ReadPtr());
+ if (attr == "material")
+ return PyString_FromString(m_materialname.ReadPtr());
+
+ if (attr == "tface")
+ return PyCObject_FromVoidPtr(m_tface, NULL);
+
+ if (attr == "gl_texture")
+ {
+ Image *ima = m_tface->tpage;
+ int bind = 0;
+ if (ima)
+ bind = ima->bindcode;
+
+ return PyInt_FromLong(bind);
+ }
+
+ if (attr == "tile")
+ return PyInt_FromLong(m_tile);
+ if (attr == "tilexrep")
+ return PyInt_FromLong(m_tilexrep);
+ if (attr == "tileyrep")
+ return PyInt_FromLong(m_tileyrep);
+
+ if (attr == "drawingmode")
+ return PyInt_FromLong(m_drawingmode);
+ if (attr == "transparent")
+ return PyInt_FromLong(m_transparant);
+ if (attr == "zsort")
+ return PyInt_FromLong(m_zsort);
+ if (attr == "lightlayer")
+ return PyInt_FromLong(m_lightlayer);
+ if (attr == "triangle")
+ return PyInt_FromLong(m_bIsTriangle);
+
+ if (attr == "diffuse")
+ return PyObjectFrom(m_diffuse);
+ if (attr == "shininess")
+ return PyFloat_FromDouble(m_shininess);
+ if (attr == "specular")
+ return PyObjectFrom(m_specular);
+ if (attr == "specularity")
+ return PyFloat_FromDouble(m_specularity);
+
+ _getattr_up(PyObjectPlus);
+}
+
+int KX_PolygonMaterial::_setattr(const STR_String &attr, PyObject *pyvalue)
+{
+ if (PyFloat_Check(pyvalue))
+ {
+ float value = PyFloat_AsDouble(pyvalue);
+ if (attr == "shininess")
+ {
+ m_shininess = value;
+ return 0;
+ }
+
+ if (attr == "specularity")
+ {
+ m_specularity = value;
+ return 0;
+ }
+ }
+
+ if (PyInt_Check(pyvalue))
+ {
+ int value = PyInt_AsLong(pyvalue);
+ if (attr == "tile")
+ {
+ m_tile = value;
+ return 0;
+ }
+
+ if (attr == "tilexrep")
+ {
+ m_tilexrep = value;
+ return 0;
+ }
+
+ if (attr == "tileyrep")
+ {
+ m_tileyrep = value;
+ return 0;
+ }
+
+ if (attr == "drawingmode")
+ {
+ m_drawingmode = value;
+ return 0;
+ }
+
+ if (attr == "transparent")
+ {
+ m_transparant = value;
+ return 0;
+ }
+
+ if (attr == "zsort")
+ {
+ m_zsort = value;
+ return 0;
+ }
+
+ if (attr == "lightlayer")
+ {
+ m_lightlayer = value;
+ return 0;
+ }
+
+ // This probably won't work...
+ if (attr == "triangle")
+ {
+ m_bIsTriangle = value;
+ return 0;
+ }
+ }
+
+ if (PySequence_Check(pyvalue))
+ {
+ if (PySequence_Size(pyvalue) == 3)
+ {
+ MT_Vector3 value;
+ if (PyVecTo(pyvalue, value))
+ {
+ if (attr == "diffuse")
+ {
+ m_diffuse = value;
+ return 0;
+ }
+
+ if (attr == "specular")
+ {
+ m_specular = value;
+ return 0;
+ }
+ }
+ }
+ }
+
+ return PyObjectPlus::_setattr(attr, pyvalue);
+}
+
+KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setCustomMaterial, "setCustomMaterial(material)")
+{
+ PyObject *material;
+ if (PyArg_ParseTuple(args, "O", &material))
+ {
+ if (m_pymaterial)
+ Py_DECREF(m_pymaterial);
+
+ m_pymaterial = material;
+ Py_INCREF(m_pymaterial);
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC(KX_PolygonMaterial, updateTexture, "updateTexture(tface, rasty)")
+{
+ PyObject *pyrasty, *pytface;
+ if (PyArg_ParseTuple(args, "O!O!", &PyCObject_Type, &pytface, &PyCObject_Type, &pyrasty))
+ {
+ MTFace *tface = (MTFace*) PyCObject_AsVoidPtr(pytface);
+ RAS_IRasterizer *rasty = (RAS_IRasterizer*) PyCObject_AsVoidPtr(pyrasty);
+ update_realtime_texture(tface, rasty->GetTime());
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setTexture, "setTexture(tface)")
+{
+ PyObject *pytface;
+ if (PyArg_ParseTuple(args, "O!", &PyCObject_Type, &pytface))
+ {
+ MTFace *tface = (MTFace*) PyCObject_AsVoidPtr(pytface);
+ set_tpage(tface);
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC(KX_PolygonMaterial, activate, "activate(rasty, cachingInfo)")
+{
+ PyObject *pyrasty, *pyCachingInfo;
+ if (PyArg_ParseTuple(args, "O!O!", &PyCObject_Type, &pyrasty, &PyCObject_Type, &pyCachingInfo))
+ {
+ RAS_IRasterizer *rasty = static_cast<RAS_IRasterizer*>(PyCObject_AsVoidPtr(pyrasty));
+ TCachingInfo *cachingInfo = static_cast<TCachingInfo*>(PyCObject_AsVoidPtr(pyCachingInfo));
+ if (rasty && cachingInfo)
+ {
+ DefaultActivate(rasty, *cachingInfo);
+ Py_Return;
+ }
+ }
+
+ return NULL;
+}
diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.h b/source/gameengine/Ketsji/KX_PolygonMaterial.h
new file mode 100644
index 00000000000..a9bcba98a78
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PolygonMaterial.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 *****
+ */
+#ifndef __KX_POLYGONMATERIAL_H__
+#define __KX_POLYGONMATERIAL_H__
+
+#include "PyObjectPlus.h"
+
+#include "RAS_MaterialBucket.h"
+#include "RAS_IRasterizer.h"
+
+struct MTFace;
+struct Material;
+struct MTex;
+
+/**
+ * Material class.
+ *
+ * This holds the shader, textures and python methods for setting the render state before
+ * rendering.
+ */
+class KX_PolygonMaterial : public PyObjectPlus, public RAS_IPolyMaterial
+{
+ Py_Header;
+private:
+ /** Blender texture face structure. */
+ MTFace* m_tface;
+ unsigned int* m_mcol;
+ Material* m_material;
+
+ PyObject* m_pymaterial;
+
+ mutable int m_pass;
+public:
+
+ KX_PolygonMaterial(const STR_String &texname,
+ Material* ma,
+ int tile,
+ int tilexrep,
+ int tileyrep,
+ int mode,
+ bool transparant,
+ bool zsort,
+ int lightlayer,
+ bool bIsTriangle,
+ void* clientobject,
+ struct MTFace* tface,
+ unsigned int* mcol,
+ PyTypeObject *T = &Type);
+ virtual ~KX_PolygonMaterial();
+
+ /**
+ * Returns the caching information for this material,
+ * This can be used to speed up the rasterizing process.
+ * @return The caching information.
+ */
+ virtual TCachingInfo GetCachingInfo(void) const
+ {
+ return (void*) this;
+ }
+
+ /**
+ * Activates the material in the (OpenGL) rasterizer.
+ * On entry, the cachingInfo contains info about the last activated material.
+ * On exit, the cachingInfo should contain updated info about this material.
+ * @param rasty The rasterizer in which the material should be active.
+ * @param cachingInfo The information about the material used to speed up rasterizing.
+ */
+ void DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const;
+ virtual bool Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const;
+
+ /**
+ * Returns the Blender texture face structure that is used for this material.
+ * @return The material's texture face.
+ */
+ MTFace* GetMTFace(void) const
+ {
+ return m_tface;
+ }
+
+ unsigned int* GetMCol(void) const
+ {
+ return m_mcol;
+ }
+
+
+ KX_PYMETHOD_DOC(KX_PolygonMaterial, updateTexture);
+ KX_PYMETHOD_DOC(KX_PolygonMaterial, setTexture);
+ KX_PYMETHOD_DOC(KX_PolygonMaterial, activate);
+
+ KX_PYMETHOD_DOC(KX_PolygonMaterial, setCustomMaterial);
+ KX_PYMETHOD_DOC(KX_PolygonMaterial, loadProgram);
+
+ virtual PyObject* _getattr(const STR_String& attr);
+ virtual int _setattr(const STR_String& attr, PyObject *pyvalue);
+};
+
+#endif // __KX_POLYGONMATERIAL_H__
+
diff --git a/source/gameengine/Ketsji/KX_PositionInterpolator.cpp b/source/gameengine/Ketsji/KX_PositionInterpolator.cpp
new file mode 100644
index 00000000000..eb8edcdca94
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PositionInterpolator.cpp
@@ -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 *****
+ */
+
+#include "KX_PositionInterpolator.h"
+#include "MT_Point3.h"
+#include "KX_IScalarInterpolator.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void KX_PositionInterpolator::Execute(float currentTime) const {
+ m_target.setValue(m_ipos[0]->GetValue(currentTime),
+ m_ipos[1]->GetValue(currentTime),
+ m_ipos[2]->GetValue(currentTime));
+}
diff --git a/source/gameengine/Ketsji/KX_PositionInterpolator.h b/source/gameengine/Ketsji/KX_PositionInterpolator.h
new file mode 100644
index 00000000000..71f5b354088
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PositionInterpolator.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 KX_POSITIONINTERPOLATOR
+#define KX_POSITIONINTERPOLATOR
+
+#include "KX_IInterpolator.h"
+
+class MT_Point3;
+class KX_IScalarInterpolator;
+
+class KX_PositionInterpolator : public KX_IInterpolator {
+public:
+ KX_PositionInterpolator(MT_Point3& target,
+ KX_IScalarInterpolator *ipos[]) :
+ m_target(target)
+ {
+ m_ipos[0] = ipos[0];
+ m_ipos[1] = ipos[1];
+ m_ipos[2] = ipos[2];
+ }
+
+ virtual void Execute(float currentTime) const;
+
+private:
+ MT_Point3& m_target;
+ KX_IScalarInterpolator *m_ipos[3];
+};
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
new file mode 100644
index 00000000000..6fbf2888bd9
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
@@ -0,0 +1,553 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_PyConstraintBinding.h"
+#include "PHY_IPhysicsEnvironment.h"
+#include "KX_ConstraintWrapper.h"
+#include "KX_VehicleWrapper.h"
+#include "KX_PhysicsObjectWrapper.h"
+#include "PHY_IPhysicsController.h"
+#include "PHY_IVehicle.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// nasty glob variable to connect scripting language
+// if there is a better way (without global), please do so!
+static PHY_IPhysicsEnvironment* g_CurrentActivePhysicsEnvironment = NULL;
+
+static char PhysicsConstraints_module_documentation[] =
+"This is the Python API for the Physics Constraints";
+
+
+static char gPySetGravity__doc__[] = "setGravity(float x,float y,float z)";
+static char gPySetDebugMode__doc__[] = "setDebugMode(int mode)";
+
+static char gPySetNumIterations__doc__[] = "setNumIterations(int numiter) This sets the number of iterations for an iterative constraint solver";
+static char gPySetNumTimeSubSteps__doc__[] = "setNumTimeSubSteps(int numsubstep) This sets the number of substeps for each physics proceed. Tradeoff quality for performance.";
+
+
+static char gPySetDeactivationTime__doc__[] = "setDeactivationTime(float time) This sets the time after which a resting rigidbody gets deactived";
+static char gPySetDeactivationLinearTreshold__doc__[] = "setDeactivationLinearTreshold(float linearTreshold)";
+static char gPySetDeactivationAngularTreshold__doc__[] = "setDeactivationAngularTreshold(float angularTreshold)";
+static char gPySetContactBreakingTreshold__doc__[] = "setContactBreakingTreshold(float breakingTreshold) Reasonable default is 0.02 (if units are meters)";
+
+static char gPySetCcdMode__doc__[] = "setCcdMode(int ccdMode) Very experimental, not recommended";
+static char gPySetSorConstant__doc__[] = "setSorConstant(float sor) Very experimental, not recommended";
+static char gPySetSolverTau__doc__[] = "setTau(float tau) Very experimental, not recommended";
+static char gPySetSolverDamping__doc__[] = "setDamping(float damping) Very experimental, not recommended";
+static char gPySetLinearAirDamping__doc__[] = "setLinearAirDamping(float damping) Very experimental, not recommended";
+static char gPySetUseEpa__doc__[] = "setUseEpa(int epa) Very experimental, not recommended";
+static char gPySetSolverType__doc__[] = "setSolverType(int solverType) Very experimental, not recommended";
+
+
+static char gPyCreateConstraint__doc__[] = "createConstraint(ob1,ob2,float restLength,float restitution,float damping)";
+static char gPyGetVehicleConstraint__doc__[] = "getVehicleConstraint(int constraintId)";
+static char gPyRemoveConstraint__doc__[] = "removeConstraint(int constraintId)";
+static char gPyGetAppliedImpulse__doc__[] = "getAppliedImpulse(int constraintId)";
+
+
+
+
+
+
+static PyObject* gPySetGravity(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float x,y,z;
+ int len = PyTuple_Size(args);
+ if ((len == 3) && PyArg_ParseTuple(args,"fff",&x,&y,&z))
+ {
+ if (PHY_GetActiveEnvironment())
+ PHY_GetActiveEnvironment()->setGravity(x,y,z);
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+static PyObject* gPySetDebugMode(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int mode;
+ if (PyArg_ParseTuple(args,"i",&mode))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setDebugMode(mode);
+
+ }
+
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+
+static PyObject* gPySetNumTimeSubSteps(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int substep;
+ if (PyArg_ParseTuple(args,"i",&substep))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setNumTimeSubSteps(substep);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+static PyObject* gPySetNumIterations(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int iter;
+ if (PyArg_ParseTuple(args,"i",&iter))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setNumIterations(iter);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+
+static PyObject* gPySetDeactivationTime(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float deactive_time;
+ if (PyArg_ParseTuple(args,"f",&deactive_time))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setDeactivationTime(deactive_time);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+static PyObject* gPySetDeactivationLinearTreshold(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float linearDeactivationTreshold;
+ if (PyArg_ParseTuple(args,"f",&linearDeactivationTreshold))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setDeactivationLinearTreshold( linearDeactivationTreshold);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+static PyObject* gPySetDeactivationAngularTreshold(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float angularDeactivationTreshold;
+ if (PyArg_ParseTuple(args,"f",&angularDeactivationTreshold))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setDeactivationAngularTreshold( angularDeactivationTreshold);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+static PyObject* gPySetContactBreakingTreshold(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float contactBreakingTreshold;
+ if (PyArg_ParseTuple(args,"f",&contactBreakingTreshold))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setContactBreakingTreshold( contactBreakingTreshold);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+static PyObject* gPySetCcdMode(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float ccdMode;
+ if (PyArg_ParseTuple(args,"f",&ccdMode))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setCcdMode( ccdMode);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+static PyObject* gPySetSorConstant(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float sor;
+ if (PyArg_ParseTuple(args,"f",&sor))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setSolverSorConstant( sor);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+static PyObject* gPySetSolverTau(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float tau;
+ if (PyArg_ParseTuple(args,"f",&tau))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setSolverTau( tau);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+static PyObject* gPySetSolverDamping(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float damping;
+ if (PyArg_ParseTuple(args,"f",&damping))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setSolverDamping( damping);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+static PyObject* gPySetLinearAirDamping(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float damping;
+ if (PyArg_ParseTuple(args,"f",&damping))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setLinearAirDamping( damping);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+static PyObject* gPySetUseEpa(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int epa;
+ if (PyArg_ParseTuple(args,"i",&epa))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setUseEpa(epa);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+static PyObject* gPySetSolverType(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int solverType;
+ if (PyArg_ParseTuple(args,"i",&solverType))
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->setSolverType(solverType);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+
+static PyObject* gPyGetVehicleConstraint(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+#if defined(_WIN64)
+ __int64 constraintid;
+ if (PyArg_ParseTuple(args,"L",&constraintid))
+#else
+ long constraintid;
+ if (PyArg_ParseTuple(args,"l",&constraintid))
+#endif
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+
+ PHY_IVehicle* vehicle = PHY_GetActiveEnvironment()->getVehicleConstraint(constraintid);
+ if (vehicle)
+ {
+ KX_VehicleWrapper* pyWrapper = new KX_VehicleWrapper(vehicle,PHY_GetActiveEnvironment());
+ return pyWrapper;
+ }
+
+ }
+ }
+
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+
+
+
+static PyObject* gPyCreateConstraint(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int physicsid=0,physicsid2 = 0,constrainttype=0,extrainfo=0;
+ int len = PyTuple_Size(args);
+ int success = 1;
+ float pivotX=1,pivotY=1,pivotZ=1,axisX=0,axisY=0,axisZ=1;
+ if (len == 3)
+ {
+ success = PyArg_ParseTuple(args,"iii",&physicsid,&physicsid2,&constrainttype);
+ }
+ else
+ if (len ==6)
+ {
+ success = PyArg_ParseTuple(args,"iiifff",&physicsid,&physicsid2,&constrainttype,
+ &pivotX,&pivotY,&pivotZ);
+ }
+ else if (len == 9)
+ {
+ success = PyArg_ParseTuple(args,"iiiffffff",&physicsid,&physicsid2,&constrainttype,
+ &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ);
+ }
+ else if (len==4)
+ {
+ success = PyArg_ParseTuple(args,"iiii",&physicsid,&physicsid2,&constrainttype,&extrainfo);
+ pivotX=extrainfo;
+ }
+
+ if (success)
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+
+ PHY_IPhysicsController* physctrl = (PHY_IPhysicsController*) physicsid;
+ PHY_IPhysicsController* physctrl2 = (PHY_IPhysicsController*) physicsid2;
+ if (physctrl) //TODO:check for existance of this pointer!
+ {
+ int constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ);
+
+ KX_ConstraintWrapper* wrap = new KX_ConstraintWrapper((enum PHY_ConstraintType)constrainttype,constraintid,PHY_GetActiveEnvironment());
+
+
+ return wrap;
+ }
+
+
+ }
+ }
+
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+
+
+static PyObject* gPyGetAppliedImpulse(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float appliedImpulse = 0.f;
+
+#if defined(_WIN64)
+ __int64 constraintid;
+ if (PyArg_ParseTuple(args,"L",&constraintid))
+#else
+ long constraintid;
+ if (PyArg_ParseTuple(args,"l",&constraintid))
+#endif
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ appliedImpulse = PHY_GetActiveEnvironment()->getAppliedImpulse(constraintid);
+ }
+ }
+
+ return PyFloat_FromDouble(appliedImpulse);
+}
+
+
+static PyObject* gPyRemoveConstraint(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+#if defined(_WIN64)
+ __int64 constraintid;
+ if (PyArg_ParseTuple(args,"L",&constraintid))
+#else
+ long constraintid;
+ if (PyArg_ParseTuple(args,"l",&constraintid))
+#endif
+ {
+ if (PHY_GetActiveEnvironment())
+ {
+ PHY_GetActiveEnvironment()->removeConstraint(constraintid);
+ }
+ }
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+static struct PyMethodDef physicsconstraints_methods[] = {
+ {"setGravity",(PyCFunction) gPySetGravity,
+ METH_VARARGS, gPySetGravity__doc__},
+ {"setDebugMode",(PyCFunction) gPySetDebugMode,
+ METH_VARARGS, gPySetDebugMode__doc__},
+
+ /// settings that influence quality of the rigidbody dynamics
+ {"setNumIterations",(PyCFunction) gPySetNumIterations,
+ METH_VARARGS, gPySetNumIterations__doc__},
+
+ {"setNumTimeSubSteps",(PyCFunction) gPySetNumTimeSubSteps,
+ METH_VARARGS, gPySetNumTimeSubSteps__doc__},
+
+ {"setDeactivationTime",(PyCFunction) gPySetDeactivationTime,
+ METH_VARARGS, gPySetDeactivationTime__doc__},
+
+ {"setDeactivationLinearTreshold",(PyCFunction) gPySetDeactivationLinearTreshold,
+ METH_VARARGS, gPySetDeactivationLinearTreshold__doc__},
+ {"setDeactivationAngularTreshold",(PyCFunction) gPySetDeactivationAngularTreshold,
+ METH_VARARGS, gPySetDeactivationAngularTreshold__doc__},
+
+ {"setContactBreakingTreshold",(PyCFunction) gPySetContactBreakingTreshold,
+ METH_VARARGS, gPySetContactBreakingTreshold__doc__},
+ {"setCcdMode",(PyCFunction) gPySetCcdMode,
+ METH_VARARGS, gPySetCcdMode__doc__},
+ {"setSorConstant",(PyCFunction) gPySetSorConstant,
+ METH_VARARGS, gPySetSorConstant__doc__},
+ {"setSolverTau",(PyCFunction) gPySetSolverTau,
+ METH_VARARGS, gPySetSolverTau__doc__},
+ {"setSolverDamping",(PyCFunction) gPySetSolverDamping,
+ METH_VARARGS, gPySetSolverDamping__doc__},
+
+ {"setLinearAirDamping",(PyCFunction) gPySetLinearAirDamping,
+ METH_VARARGS, gPySetLinearAirDamping__doc__},
+
+ {"setUseEpa",(PyCFunction) gPySetUseEpa,
+ METH_VARARGS, gPySetUseEpa__doc__},
+ {"setSolverType",(PyCFunction) gPySetSolverType,
+ METH_VARARGS, gPySetSolverType__doc__},
+
+
+ {"createConstraint",(PyCFunction) gPyCreateConstraint,
+ METH_VARARGS, gPyCreateConstraint__doc__},
+ {"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint,
+ METH_VARARGS, gPyGetVehicleConstraint__doc__},
+
+ {"removeConstraint",(PyCFunction) gPyRemoveConstraint,
+ METH_VARARGS, gPyRemoveConstraint__doc__},
+ {"getAppliedImpulse",(PyCFunction) gPyGetAppliedImpulse,
+ METH_VARARGS, gPyGetAppliedImpulse__doc__},
+
+
+ //sentinel
+ { NULL, (PyCFunction) NULL, 0, NULL }
+};
+
+
+
+PyObject* initPythonConstraintBinding()
+{
+
+ PyObject* ErrorObject;
+ PyObject* m;
+ PyObject* d;
+
+
+ m = Py_InitModule4("PhysicsConstraints", physicsconstraints_methods,
+ PhysicsConstraints_module_documentation,
+ (PyObject*)NULL,PYTHON_API_VERSION);
+
+ // Add some symbolic constants to the module
+ d = PyModule_GetDict(m);
+ ErrorObject = PyString_FromString("PhysicsConstraints.error");
+ PyDict_SetItemString(d, "error", ErrorObject);
+
+ // XXXX Add constants here
+
+ // Check for errors
+ if (PyErr_Occurred())
+ {
+ Py_FatalError("can't initialize module PhysicsConstraints");
+ }
+
+ return d;
+}
+
+
+void KX_RemovePythonConstraintBinding()
+{
+}
+
+void PHY_SetActiveEnvironment(class PHY_IPhysicsEnvironment* env)
+{
+ g_CurrentActivePhysicsEnvironment = env;
+}
+
+PHY_IPhysicsEnvironment* PHY_GetActiveEnvironment()
+{
+ return g_CurrentActivePhysicsEnvironment;
+}
+
diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.h b/source/gameengine/Ketsji/KX_PyConstraintBinding.h
new file mode 100644
index 00000000000..a8651a175c2
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.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 PHY_PYTHON_CONSTRAINTBINDING
+#define PHY_PYTHON_CONSTRAINTBINDING
+
+#include <Python.h>
+
+PyObject* initPythonConstraintBinding();
+void PHY_RemovePythonConstraintBinding();
+void PHY_SetActiveEnvironment(class PHY_IPhysicsEnvironment* env);
+PHY_IPhysicsEnvironment* PHY_GetActiveEnvironment();
+
+
+#endif //PHY_PYTHON_CONSTRAINTBINDING
+
diff --git a/source/gameengine/Ketsji/KX_PyMath.cpp b/source/gameengine/Ketsji/KX_PyMath.cpp
new file mode 100644
index 00000000000..1eee4e7043c
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PyMath.cpp
@@ -0,0 +1,114 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Initialize Python thingies.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif //WIN32
+
+#include "MT_Vector3.h"
+#include "MT_Vector4.h"
+#include "MT_Matrix4x4.h"
+#include "MT_Point2.h"
+
+#include "ListValue.h"
+
+#include "KX_Python.h"
+
+bool PyObject_IsMT_Matrix(PyObject *pymat, unsigned int rank)
+{
+ if (!pymat)
+ return false;
+
+ unsigned int y;
+ if (PySequence_Check(pymat))
+ {
+ unsigned int rows = PySequence_Size(pymat);
+ if (rows != rank)
+ return false;
+
+ bool ismatrix = true;
+ for (y = 0; y < rank && ismatrix; y++)
+ {
+ PyObject *pyrow = PySequence_GetItem(pymat, y); /* new ref */
+ if (PySequence_Check(pyrow))
+ {
+ if (((unsigned int)PySequence_Size(pyrow)) != rank)
+ ismatrix = false;
+ } else
+ ismatrix = false;
+ Py_DECREF(pyrow);
+ }
+ return ismatrix;
+ }
+ return false;
+}
+
+
+PyObject* PyObjectFrom(const MT_Matrix4x4 &mat)
+{
+ return Py_BuildValue("[[ffff][ffff][ffff][ffff]]",
+ mat[0][0], mat[0][1], mat[0][2], mat[0][3],
+ mat[1][0], mat[1][1], mat[1][2], mat[1][3],
+ mat[2][0], mat[2][1], mat[2][2], mat[2][3],
+ mat[3][0], mat[3][1], mat[3][2], mat[3][3]);
+}
+
+PyObject* PyObjectFrom(const MT_Matrix3x3 &mat)
+{
+ return Py_BuildValue("[[fff][fff][fff]]",
+ mat[0][0], mat[0][1], mat[0][2],
+ mat[1][0], mat[1][1], mat[1][2],
+ mat[2][0], mat[2][1], mat[2][2]);
+}
+
+PyObject* PyObjectFrom(const MT_Tuple4 &vec)
+{
+ return Py_BuildValue("[ffff]",
+ vec[0], vec[1], vec[2], vec[3]);
+}
+
+PyObject* PyObjectFrom(const MT_Tuple3 &vec)
+{
+ return Py_BuildValue("[fff]",
+ vec[0], vec[1], vec[2]);
+}
+
+PyObject* PyObjectFrom(const MT_Tuple2 &vec)
+{
+ return Py_BuildValue("[ff]",
+ vec[0], vec[1]);
+}
diff --git a/source/gameengine/Ketsji/KX_PyMath.h b/source/gameengine/Ketsji/KX_PyMath.h
new file mode 100644
index 00000000000..96a3431fe07
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PyMath.h
@@ -0,0 +1,164 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Initialize Python thingies.
+ */
+
+#ifndef __KX_PYMATH_H__
+#define __KX_PYMATH_H__
+
+#include "MT_Point2.h"
+#include "MT_Point3.h"
+#include "MT_Vector2.h"
+#include "MT_Vector3.h"
+#include "MT_Vector4.h"
+#include "MT_Matrix3x3.h"
+#include "MT_Matrix4x4.h"
+
+#include "KX_Python.h"
+
+inline unsigned int Size(const MT_Matrix4x4&) { return 4; }
+inline unsigned int Size(const MT_Matrix3x3&) { return 3; }
+inline unsigned int Size(const MT_Tuple2&) { return 2; }
+inline unsigned int Size(const MT_Tuple3&) { return 3; }
+inline unsigned int Size(const MT_Tuple4&) { return 4; }
+
+/**
+ * Converts the given python matrix to an MT class.
+ */
+template<class T>
+bool PyMatTo(PyObject* pymat, T& mat)
+{
+ bool noerror = true;
+ mat.setIdentity();
+ if (PySequence_Check(pymat))
+ {
+ unsigned int rows = PySequence_Size(pymat);
+ if (rows != Size(mat))
+ return false;
+
+ for (unsigned int y = 0; noerror && y < Size(mat); y++)
+ {
+ PyObject *pyrow = PySequence_GetItem(pymat, y); /* new ref */
+ if (!PyErr_Occurred() && PySequence_Check(pyrow))
+ {
+ unsigned int cols = PySequence_Size(pyrow);
+ if (cols != Size(mat))
+ noerror = false;
+ else
+ {
+ for( unsigned int x = 0; x < Size(mat); x++)
+ {
+ PyObject *item = PySequence_GetItem(pyrow, x); /* new ref */
+ mat[y][x] = PyFloat_AsDouble(item);
+ Py_DECREF(item);
+ }
+ }
+ } else
+ noerror = false;
+ Py_DECREF(pyrow);
+ }
+ } else
+ noerror = false;
+
+ return noerror;
+}
+
+/**
+ * Converts a python list to a MT class.
+ */
+template<class T>
+bool PyVecTo(PyObject* pyval, T& vec)
+{
+ if (PySequence_Check(pyval))
+ {
+ unsigned int numitems = PySequence_Size(pyval);
+ if (numitems != Size(vec))
+ return false;
+
+ for (unsigned int x = 0; x < numitems; x++)
+ {
+ PyObject *item = PySequence_GetItem(pyval, x); /* new ref */
+ vec[x] = PyFloat_AsDouble(item);
+ Py_DECREF(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Converts a python argument to an MT class.
+ * This paramater expects arguments as passed to a python method.
+ */
+template<class T>
+bool PyVecArgTo(PyObject* args, T& vec)
+{
+ PyObject* pylist;
+ if (PyArg_ParseTuple(args,"O",&pylist))
+ return PyVecTo(pylist, vec);
+
+ return false;
+}
+
+/**
+ * Converts an MT_Matrix4x4 to a python object.
+ */
+PyObject* PyObjectFrom(const MT_Matrix4x4 &mat);
+
+/**
+ * Converts an MT_Matrix3x3 to a python object.
+ */
+PyObject* PyObjectFrom(const MT_Matrix3x3 &mat);
+
+/**
+ * Converts an MT_Tuple2 to a python object.
+ */
+PyObject* PyObjectFrom(const MT_Tuple2 &vec);
+
+/**
+ * Converts an MT_Tuple3 to a python object
+ */
+PyObject* PyObjectFrom(const MT_Tuple3 &vec);
+
+/**
+ * Converts an MT_Tuple4 to a python object.
+ */
+PyObject* PyObjectFrom(const MT_Tuple4 &pos);
+
+/**
+ * True if the given PyObject can be converted to an MT_Matrix
+ * @param rank = 3 (for MT_Matrix3x3) or 4 (for MT_Matrix4x4)
+ */
+bool PyObject_IsMT_Matrix(PyObject *pymat, unsigned int rank);
+
+#endif
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
new file mode 100644
index 00000000000..1a3a0490d21
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -0,0 +1,1157 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Initialize Python thingies.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+#endif // WIN32
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif //WIN32
+
+#include "KX_PythonInit.h"
+//python physics binding
+#include "KX_PyConstraintBinding.h"
+
+#include "KX_KetsjiEngine.h"
+
+#include "SCA_IInputDevice.h"
+#include "SCA_PropertySensor.h"
+#include "SCA_RandomActuator.h"
+#include "KX_ConstraintActuator.h"
+#include "KX_IpoActuator.h"
+#include "KX_SoundActuator.h"
+#include "BL_ActionActuator.h"
+#include "RAS_IRasterizer.h"
+#include "RAS_ICanvas.h"
+#include "MT_Vector3.h"
+#include "MT_Point3.h"
+#include "ListValue.h"
+#include "KX_Scene.h"
+#include "SND_DeviceManager.h"
+
+#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
+#include "BL_Shader.h"
+
+#include "KX_PyMath.h"
+
+#include "PHY_IPhysicsEnvironment.h"
+// FIXME: Enable for access to blender python modules. This is disabled because
+// python has dependencies on a lot of other modules and is a pain to link.
+//#define USE_BLENDER_PYTHON
+#ifdef USE_BLENDER_PYTHON
+//#include "BPY_extern.h"
+#endif
+
+static void setSandbox(TPythonSecurityLevel level);
+
+
+// 'local' copy of canvas ptr, for window height/width python scripts
+static RAS_ICanvas* gp_Canvas = NULL;
+static KX_Scene* gp_KetsjiScene = NULL;
+static RAS_IRasterizer* gp_Rasterizer = NULL;
+
+void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color)
+{
+ if (gp_Rasterizer)
+ gp_Rasterizer->DrawDebugLine(from,to,color);
+}
+
+/* Macro for building the keyboard translation */
+//#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, PyInt_FromLong(SCA_IInputDevice::KX_##name))
+#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, PyInt_FromLong(name))
+/* For the defines for types from logic bricks, we do stuff explicitly... */
+#define KX_MACRO_addTypesToDict(dict, name, name2) PyDict_SetItemString(dict, #name, PyInt_FromLong(name2))
+
+
+// temporarily python stuff, will be put in another place later !
+#include "KX_Python.h"
+#include "SCA_PythonController.h"
+// List of methods defined in the module
+
+static PyObject* ErrorObject;
+STR_String gPyGetRandomFloat_doc="getRandomFloat returns a random floating point value in the range [0..1)";
+
+static PyObject* gPyGetRandomFloat(PyObject*,
+ PyObject*,
+ PyObject*)
+{
+ return PyFloat_FromDouble(MT_random());
+}
+
+static PyObject* gPySetGravity(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ MT_Vector3 vec = MT_Vector3(0., 0., 0.);
+ if (PyVecArgTo(args, vec))
+ {
+ if (gp_KetsjiScene)
+ gp_KetsjiScene->SetGravity(vec);
+
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+
+static bool usedsp = false;
+
+// this gets a pointer to an array filled with floats
+static PyObject* gPyGetSpectrum(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
+
+ PyObject* resultlist = PyList_New(512);
+
+ if (audiodevice)
+ {
+ if (!usedsp)
+ {
+ audiodevice->StartUsingDSP();
+ usedsp = true;
+ }
+
+ float* spectrum = audiodevice->GetSpectrum();
+
+ for (int index = 0; index < 512; index++)
+ {
+ PyList_SetItem(resultlist, index, PyFloat_FromDouble(spectrum[index]));
+ }
+ }
+
+ return resultlist;
+}
+
+
+
+static PyObject* gPyStartDSP(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
+
+ if (audiodevice)
+ {
+ if (!usedsp)
+ {
+ audiodevice->StartUsingDSP();
+ usedsp = true;
+ Py_Return;
+ }
+ }
+ return NULL;
+}
+
+
+
+static PyObject* gPyStopDSP(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
+
+ if (audiodevice)
+ {
+ if (usedsp)
+ {
+ audiodevice->StopUsingDSP();
+ usedsp = false;
+ Py_Return;
+ }
+ }
+ return NULL;
+}
+
+static PyObject* gPySetLogicTicRate(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ float ticrate;
+ if (PyArg_ParseTuple(args, "f", &ticrate))
+ {
+ KX_KetsjiEngine::SetTicRate(ticrate);
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+static PyObject* gPyGetLogicTicRate(PyObject*, PyObject*, PyObject*)
+{
+ return PyFloat_FromDouble(KX_KetsjiEngine::GetTicRate());
+}
+
+static PyObject* gPySetPhysicsTicRate(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ float ticrate;
+ if (PyArg_ParseTuple(args, "f", &ticrate))
+ {
+
+ PHY_GetActiveEnvironment()->setFixedTimeStep(true,ticrate);
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+static PyObject* gPySetPhysicsDebug(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ int debugMode;
+ if (PyArg_ParseTuple(args, "i", &debugMode))
+ {
+ PHY_GetActiveEnvironment()->setDebugMode(debugMode);
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+
+
+static PyObject* gPyGetPhysicsTicRate(PyObject*, PyObject*, PyObject*)
+{
+ return PyFloat_FromDouble(PHY_GetActiveEnvironment()->getFixedTimeStep());
+}
+
+static STR_String gPyGetCurrentScene_doc =
+"getCurrentScene()\n"
+"Gets a reference to the current scene.\n";
+static PyObject* gPyGetCurrentScene(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ Py_INCREF(gp_KetsjiScene);
+ return (PyObject*) gp_KetsjiScene;
+}
+
+static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *)
+{
+#define pprint(x) std::cout << x << std::endl;
+ bgl::BL_EXTInfo ext = bgl::RAS_EXT_support;
+ bool count=0;
+ bool support=0;
+ pprint("Supported Extensions...");
+#ifdef GL_ARB_shader_objects
+ pprint(" GL_ARB_shader_objects supported? "<< (ext._ARB_shader_objects?"yes.":"no."));
+ count = 1;
+#endif
+
+#ifdef GL_ARB_vertex_shader
+ support= ext._ARB_vertex_shader;
+ pprint(" GL_ARB_vertex_shader supported? "<< (support?"yes.":"no."));
+ count = 1;
+ if(support){
+ pprint(" ----------Details----------");
+ int max=0;
+ glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, (GLint*)&max);
+ pprint(" Max uniform components." << max);
+
+ glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, (GLint*)&max);
+ pprint(" Max varying floats." << max);
+
+ glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max);
+ pprint(" Max vertex texture units." << max);
+
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max);
+ pprint(" Max combined texture units." << max);
+ pprint("");
+ }
+#endif
+#ifdef GL_ARB_fragment_shader
+ support=ext._ARB_fragment_shader;
+ pprint(" GL_ARB_fragment_shader supported? "<< (support?"yes.":"no."));
+ count = 1;
+ if(support){
+ pprint(" ----------Details----------");
+ int max=0;
+ glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, (GLint*)&max);
+ pprint(" Max uniform components." << max);
+ pprint("");
+ }
+#endif
+#ifdef GL_ARB_texture_cube_map
+ support = ext._ARB_texture_cube_map;
+ pprint(" GL_ARB_texture_cube_map supported? "<< (support?"yes.":"no."));
+ count = 1;
+ if(support){
+ pprint(" ----------Details----------");
+ int size=0;
+ glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, (GLint*)&size);
+ pprint(" Max cubemap size." << size);
+ pprint("");
+ }
+#endif
+#ifdef GL_ARB_multitexture
+ support = ext._ARB_multitexture;
+ count = 1;
+ pprint(" GL_ARB_multitexture supported? "<< (support?"yes.":"no."));
+ if(support){
+ pprint(" ----------Details----------");
+ int units=0;
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&units);
+ pprint(" Max texture units available. " << units);
+ pprint("");
+ }
+#endif
+#ifdef GL_ARB_texture_env_combine
+ pprint(" GL_ARB_texture_env_combine supported? "<< (ext._ARB_texture_env_combine?"yes.":"no."));
+ count = 1;
+#endif
+ if(!count)
+ pprint("No extenstions are used in this build");
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static struct PyMethodDef game_methods[] = {
+ {"getCurrentController",
+ (PyCFunction) SCA_PythonController::sPyGetCurrentController,
+ METH_VARARGS, SCA_PythonController::sPyGetCurrentController__doc__},
+ {"getCurrentScene", (PyCFunction) gPyGetCurrentScene,
+ METH_VARARGS, gPyGetCurrentScene_doc.Ptr()},
+ {"addActiveActuator",(PyCFunction) SCA_PythonController::sPyAddActiveActuator,
+ METH_VARARGS, SCA_PythonController::sPyAddActiveActuator__doc__},
+ {"getRandomFloat",(PyCFunction) gPyGetRandomFloat,
+ METH_VARARGS,gPyGetRandomFloat_doc.Ptr()},
+ {"setGravity",(PyCFunction) gPySetGravity, METH_VARARGS,"set Gravitation"},
+ {"getSpectrum",(PyCFunction) gPyGetSpectrum, METH_VARARGS,"get audio spectrum"},
+ {"stopDSP",(PyCFunction) gPyStopDSP, METH_VARARGS,"stop using the audio dsp (for performance reasons)"},
+ {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_VARARGS, "Gets the logic tic rate"},
+ {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, "Sets the logic tic rate"},
+ {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_VARARGS, "Gets the physics tic rate"},
+ {"setPhysicsTicRate", (PyCFunction) gPySetPhysicsTicRate, METH_VARARGS, "Sets the physics tic rate"},
+ {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, "Prints GL Extension Info"},
+ {NULL, (PyCFunction) NULL, 0, NULL }
+};
+
+
+static PyObject* gPyGetWindowHeight(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ int height = (gp_Canvas ? gp_Canvas->GetHeight() : 0);
+
+ PyObject* heightval = PyInt_FromLong(height);
+ return heightval;
+}
+
+
+
+static PyObject* gPyGetWindowWidth(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+
+
+ int width = (gp_Canvas ? gp_Canvas->GetWidth() : 0);
+
+ PyObject* widthval = PyInt_FromLong(width);
+ return widthval;
+}
+
+
+
+// temporarility visibility thing, will be moved to rasterizer/renderer later
+bool gUseVisibilityTemp = false;
+
+static PyObject* gPyEnableVisibility(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ int visible;
+ if (PyArg_ParseTuple(args,"i",&visible))
+ {
+ gUseVisibilityTemp = (visible != 0);
+ }
+ else
+ {
+ Py_Return;
+ }
+ Py_Return;
+}
+
+
+
+static PyObject* gPyShowMouse(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ int visible;
+ if (PyArg_ParseTuple(args,"i",&visible))
+ {
+ if (visible)
+ {
+ if (gp_Canvas)
+ gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
+ } else
+ {
+ if (gp_Canvas)
+ gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
+ }
+ }
+
+ Py_Return;
+}
+
+
+
+static PyObject* gPySetMousePosition(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ int x,y;
+ if (PyArg_ParseTuple(args,"ii",&x,&y))
+ {
+ if (gp_Canvas)
+ gp_Canvas->SetMousePosition(x,y);
+ }
+
+ Py_Return;
+}
+
+static PyObject* gPySetEyeSeparation(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ float sep;
+ if (PyArg_ParseTuple(args, "f", &sep))
+ {
+ if (gp_Rasterizer)
+ gp_Rasterizer->SetEyeSeparation(sep);
+
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+static PyObject* gPyGetEyeSeparation(PyObject*, PyObject*, PyObject*)
+{
+ if (gp_Rasterizer)
+ return PyFloat_FromDouble(gp_Rasterizer->GetEyeSeparation());
+
+ return NULL;
+}
+
+static PyObject* gPySetFocalLength(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ float focus;
+ if (PyArg_ParseTuple(args, "f", &focus))
+ {
+ if (gp_Rasterizer)
+ gp_Rasterizer->SetFocalLength(focus);
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+static PyObject* gPyGetFocalLength(PyObject*, PyObject*, PyObject*)
+{
+ if (gp_Rasterizer)
+ return PyFloat_FromDouble(gp_Rasterizer->GetFocalLength());
+ return NULL;
+}
+
+static PyObject* gPySetBackgroundColor(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+
+ MT_Vector4 vec = MT_Vector4(0., 0., 0.3, 0.);
+ if (PyVecArgTo(args, vec))
+ {
+ if (gp_Canvas)
+ {
+ gp_Rasterizer->SetBackColor(vec[0], vec[1], vec[2], vec[3]);
+ }
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+
+
+static PyObject* gPySetMistColor(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+
+ MT_Vector3 vec = MT_Vector3(0., 0., 0.);
+ if (PyVecArgTo(args, vec))
+ {
+ if (gp_Rasterizer)
+ {
+ gp_Rasterizer->SetFogColor(vec[0], vec[1], vec[2]);
+ }
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+
+
+static PyObject* gPySetMistStart(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+
+ float miststart;
+ if (PyArg_ParseTuple(args,"f",&miststart))
+ {
+ if (gp_Rasterizer)
+ {
+ gp_Rasterizer->SetFogStart(miststart);
+ }
+ }
+ Py_Return;
+}
+
+
+
+static PyObject* gPySetMistEnd(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+
+ float mistend;
+ if (PyArg_ParseTuple(args,"f",&mistend))
+ {
+ if (gp_Rasterizer)
+ {
+ gp_Rasterizer->SetFogEnd(mistend);
+ }
+ }
+ Py_Return;
+}
+
+
+static PyObject* gPySetAmbientColor(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+
+ MT_Vector3 vec = MT_Vector3(0., 0., 0.);
+ if (PyVecArgTo(args, vec))
+ {
+ if (gp_Rasterizer)
+ {
+ gp_Rasterizer->SetAmbientColor(vec[0], vec[1], vec[2]);
+ }
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+
+
+
+static PyObject* gPyMakeScreenshot(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ char* filename;
+ if (PyArg_ParseTuple(args,"s",&filename))
+ {
+ if (gp_Canvas)
+ {
+ gp_Canvas->MakeScreenShot(filename);
+ }
+ }
+ Py_Return;
+}
+
+static PyObject* gPyEnableMotionBlur(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ float motionblurvalue;
+ if (PyArg_ParseTuple(args,"f",&motionblurvalue))
+ {
+ if(gp_Rasterizer)
+ {
+ gp_Rasterizer->EnableMotionBlur(motionblurvalue);
+ }
+ }
+ Py_Return;
+}
+
+static PyObject* gPyDisableMotionBlur(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ if(gp_Rasterizer)
+ {
+ gp_Rasterizer->DisableMotionBlur();
+ }
+ Py_Return;
+}
+
+STR_String gPyGetWindowHeight__doc__="getWindowHeight doc";
+STR_String gPyGetWindowWidth__doc__="getWindowWidth doc";
+STR_String gPyEnableVisibility__doc__="enableVisibility doc";
+STR_String gPyMakeScreenshot__doc__="make Screenshot doc";
+STR_String gPyShowMouse__doc__="showMouse(bool visible)";
+STR_String gPySetMousePosition__doc__="setMousePosition(int x,int y)";
+
+static struct PyMethodDef rasterizer_methods[] = {
+ {"getWindowWidth",(PyCFunction) gPyGetWindowWidth,
+ METH_VARARGS, gPyGetWindowWidth__doc__.Ptr()},
+ {"getWindowHeight",(PyCFunction) gPyGetWindowHeight,
+ METH_VARARGS, gPyGetWindowHeight__doc__.Ptr()},
+ {"makeScreenshot",(PyCFunction)gPyMakeScreenshot,
+ METH_VARARGS, gPyMakeScreenshot__doc__.Ptr()},
+ {"enableVisibility",(PyCFunction) gPyEnableVisibility,
+ METH_VARARGS, gPyEnableVisibility__doc__.Ptr()},
+ {"showMouse",(PyCFunction) gPyShowMouse,
+ METH_VARARGS, gPyShowMouse__doc__.Ptr()},
+ {"setMousePosition",(PyCFunction) gPySetMousePosition,
+ METH_VARARGS, gPySetMousePosition__doc__.Ptr()},
+ {"setBackgroundColor",(PyCFunction)gPySetBackgroundColor,METH_VARARGS,"set Background Color (rgb)"},
+ {"setAmbientColor",(PyCFunction)gPySetAmbientColor,METH_VARARGS,"set Ambient Color (rgb)"},
+ {"setMistColor",(PyCFunction)gPySetMistColor,METH_VARARGS,"set Mist Color (rgb)"},
+ {"setMistStart",(PyCFunction)gPySetMistStart,METH_VARARGS,"set Mist Start(rgb)"},
+ {"setMistEnd",(PyCFunction)gPySetMistEnd,METH_VARARGS,"set Mist End(rgb)"},
+ {"enableMotionBlur",(PyCFunction)gPyEnableMotionBlur,METH_VARARGS,"enable motion blur"},
+ {"disableMotionBlur",(PyCFunction)gPyDisableMotionBlur,METH_VARARGS,"disable motion blur"},
+
+
+ {"setEyeSeparation", (PyCFunction) gPySetEyeSeparation, METH_VARARGS, "set the eye separation for stereo mode"},
+ {"getEyeSeparation", (PyCFunction) gPyGetEyeSeparation, METH_VARARGS, "get the eye separation for stereo mode"},
+ {"setFocalLength", (PyCFunction) gPySetFocalLength, METH_VARARGS, "set the focal length for stereo mode"},
+ {"getFocalLength", (PyCFunction) gPyGetFocalLength, METH_VARARGS, "get the focal length for stereo mode"},
+ { NULL, (PyCFunction) NULL, 0, NULL }
+};
+
+
+
+// Initialization function for the module (*must* be called initGameLogic)
+
+static char GameLogic_module_documentation[] =
+"This is the Python API for the game engine of GameLogic"
+;
+
+static char Rasterizer_module_documentation[] =
+"This is the Python API for the game engine of Rasterizer"
+;
+
+
+
+PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook
+{
+ PyObject* m;
+ PyObject* d;
+
+ gp_KetsjiScene = scene;
+
+ gUseVisibilityTemp=false;
+
+ // Create the module and add the functions
+ m = Py_InitModule4("GameLogic", game_methods,
+ GameLogic_module_documentation,
+ (PyObject*)NULL,PYTHON_API_VERSION);
+
+ // Add some symbolic constants to the module
+ d = PyModule_GetDict(m);
+
+ ErrorObject = PyString_FromString("GameLogic.error");
+ PyDict_SetItemString(d, "error", ErrorObject);
+
+ // XXXX Add constants here
+ /* To use logic bricks, we need some sort of constants. Here, we associate */
+ /* constants and sumbolic names. Add them to dictionary d. */
+
+ /* 1. true and false: needed for everyone */
+ KX_MACRO_addTypesToDict(d, KX_TRUE, SCA_ILogicBrick::KX_TRUE);
+ KX_MACRO_addTypesToDict(d, KX_FALSE, SCA_ILogicBrick::KX_FALSE);
+
+ /* 2. Property sensor */
+ KX_MACRO_addTypesToDict(d, KX_PROPSENSOR_EQUAL, SCA_PropertySensor::KX_PROPSENSOR_EQUAL);
+ KX_MACRO_addTypesToDict(d, KX_PROPSENSOR_NOTEQUAL, SCA_PropertySensor::KX_PROPSENSOR_NOTEQUAL);
+ KX_MACRO_addTypesToDict(d, KX_PROPSENSOR_INTERVAL, SCA_PropertySensor::KX_PROPSENSOR_INTERVAL);
+ KX_MACRO_addTypesToDict(d, KX_PROPSENSOR_CHANGED, SCA_PropertySensor::KX_PROPSENSOR_CHANGED);
+ KX_MACRO_addTypesToDict(d, KX_PROPSENSOR_EXPRESSION, SCA_PropertySensor::KX_PROPSENSOR_EXPRESSION);
+
+ /* 3. Constraint actuator */
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_LOCX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCX);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_LOCY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCY);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_LOCZ, KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCZ);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ROTX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTX);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ROTY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTY);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ROTZ, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTZ);
+
+ /* 4. Ipo actuator, simple part */
+ KX_MACRO_addTypesToDict(d, KX_IPOACT_PLAY, KX_IpoActuator::KX_ACT_IPO_PLAY);
+ KX_MACRO_addTypesToDict(d, KX_IPOACT_PINGPONG, KX_IpoActuator::KX_ACT_IPO_PINGPONG);
+ KX_MACRO_addTypesToDict(d, KX_IPOACT_FLIPPER, KX_IpoActuator::KX_ACT_IPO_FLIPPER);
+ KX_MACRO_addTypesToDict(d, KX_IPOACT_LOOPSTOP, KX_IpoActuator::KX_ACT_IPO_LOOPSTOP);
+ KX_MACRO_addTypesToDict(d, KX_IPOACT_LOOPEND, KX_IpoActuator::KX_ACT_IPO_LOOPEND);
+
+ /* 5. Random distribution types */
+ KX_MACRO_addTypesToDict(d, KX_RANDOMACT_BOOL_CONST, SCA_RandomActuator::KX_RANDOMACT_BOOL_CONST);
+ KX_MACRO_addTypesToDict(d, KX_RANDOMACT_BOOL_UNIFORM, SCA_RandomActuator::KX_RANDOMACT_BOOL_UNIFORM);
+ KX_MACRO_addTypesToDict(d, KX_RANDOMACT_BOOL_BERNOUILLI, SCA_RandomActuator::KX_RANDOMACT_BOOL_BERNOUILLI);
+ KX_MACRO_addTypesToDict(d, KX_RANDOMACT_INT_CONST, SCA_RandomActuator::KX_RANDOMACT_INT_CONST);
+ KX_MACRO_addTypesToDict(d, KX_RANDOMACT_INT_UNIFORM, SCA_RandomActuator::KX_RANDOMACT_INT_UNIFORM);
+ KX_MACRO_addTypesToDict(d, KX_RANDOMACT_INT_POISSON, SCA_RandomActuator::KX_RANDOMACT_INT_POISSON);
+ KX_MACRO_addTypesToDict(d, KX_RANDOMACT_FLOAT_CONST, SCA_RandomActuator::KX_RANDOMACT_FLOAT_CONST);
+ KX_MACRO_addTypesToDict(d, KX_RANDOMACT_FLOAT_UNIFORM, SCA_RandomActuator::KX_RANDOMACT_FLOAT_UNIFORM);
+ KX_MACRO_addTypesToDict(d, KX_RANDOMACT_FLOAT_NORMAL, SCA_RandomActuator::KX_RANDOMACT_FLOAT_NORMAL);
+ KX_MACRO_addTypesToDict(d, KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL, SCA_RandomActuator::KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL);
+
+ /* 6. Sound actuator */
+ KX_MACRO_addTypesToDict(d, KX_SOUNDACT_PLAYSTOP, KX_SoundActuator::KX_SOUNDACT_PLAYSTOP);
+ KX_MACRO_addTypesToDict(d, KX_SOUNDACT_PLAYEND, KX_SoundActuator::KX_SOUNDACT_PLAYEND);
+ KX_MACRO_addTypesToDict(d, KX_SOUNDACT_LOOPSTOP, KX_SoundActuator::KX_SOUNDACT_LOOPSTOP);
+ KX_MACRO_addTypesToDict(d, KX_SOUNDACT_LOOPEND, KX_SoundActuator::KX_SOUNDACT_LOOPEND);
+ KX_MACRO_addTypesToDict(d, KX_SOUNDACT_LOOPBIDIRECTIONAL, KX_SoundActuator::KX_SOUNDACT_LOOPBIDIRECTIONAL);
+ KX_MACRO_addTypesToDict(d, KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP, KX_SoundActuator::KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP);
+
+ /* 7. Action actuator */
+ KX_MACRO_addTypesToDict(d, KX_ACTIONACT_PLAY, BL_ActionActuator::KX_ACT_ACTION_PLAY);
+ KX_MACRO_addTypesToDict(d, KX_ACTIONACT_FLIPPER, BL_ActionActuator::KX_ACT_ACTION_FLIPPER);
+ KX_MACRO_addTypesToDict(d, KX_ACTIONACT_LOOPSTOP, BL_ActionActuator::KX_ACT_ACTION_LOOPSTOP);
+ KX_MACRO_addTypesToDict(d, KX_ACTIONACT_LOOPEND, BL_ActionActuator::KX_ACT_ACTION_LOOPEND);
+ KX_MACRO_addTypesToDict(d, KX_ACTIONACT_PROPERTY, BL_ActionActuator::KX_ACT_ACTION_PROPERTY);
+
+ /*8. GL_BlendFunc */
+ KX_MACRO_addTypesToDict(d, BL_ZERO, GL_ZERO);
+ KX_MACRO_addTypesToDict(d, BL_ONE, GL_ONE);
+ KX_MACRO_addTypesToDict(d, BL_SRC_COLOR, GL_SRC_COLOR);
+ KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
+ KX_MACRO_addTypesToDict(d, BL_DST_COLOR, GL_DST_COLOR);
+ KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_DST_COLOR);
+ KX_MACRO_addTypesToDict(d, BL_SRC_ALPHA, GL_SRC_ALPHA);
+ KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ KX_MACRO_addTypesToDict(d, BL_DST_ALPHA, GL_DST_ALPHA);
+ KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
+ KX_MACRO_addTypesToDict(d, BL_SRC_ALPHA_SATURATE, GL_SRC_ALPHA_SATURATE);
+
+
+ /* 9. UniformTypes */
+ KX_MACRO_addTypesToDict(d, SHD_TANGENT, BL_Shader::SHD_TANGENT);
+ KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX, BL_Shader::MODELVIEWMATRIX);
+ KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX_TRANSPOSE, BL_Shader::MODELVIEWMATRIX_TRANSPOSE);
+ KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX_INVERSE, BL_Shader::MODELVIEWMATRIX_INVERSE);
+ KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX_INVERSETRANSPOSE, BL_Shader::MODELVIEWMATRIX_INVERSETRANSPOSE);
+ KX_MACRO_addTypesToDict(d, MODELMATRIX, BL_Shader::MODELMATRIX);
+ KX_MACRO_addTypesToDict(d, MODELMATRIX_TRANSPOSE, BL_Shader::MODELMATRIX_TRANSPOSE);
+ KX_MACRO_addTypesToDict(d, MODELMATRIX_INVERSE, BL_Shader::MODELMATRIX_INVERSE);
+ KX_MACRO_addTypesToDict(d, MODELMATRIX_INVERSETRANSPOSE, BL_Shader::MODELMATRIX_INVERSETRANSPOSE);
+ KX_MACRO_addTypesToDict(d, VIEWMATRIX, BL_Shader::VIEWMATRIX);
+ KX_MACRO_addTypesToDict(d, VIEWMATRIX_TRANSPOSE, BL_Shader::VIEWMATRIX_TRANSPOSE);
+ KX_MACRO_addTypesToDict(d, VIEWMATRIX_INVERSE, BL_Shader::VIEWMATRIX_INVERSE);
+ KX_MACRO_addTypesToDict(d, VIEWMATRIX_INVERSETRANSPOSE, BL_Shader::VIEWMATRIX_INVERSETRANSPOSE);
+ KX_MACRO_addTypesToDict(d, CAM_POS, BL_Shader::CAM_POS);
+ KX_MACRO_addTypesToDict(d, CONSTANT_TIMER, BL_Shader::CONSTANT_TIMER);
+
+ // Check for errors
+ if (PyErr_Occurred())
+ {
+ Py_FatalError("can't initialize module GameLogic");
+ }
+
+ return d;
+}
+
+void dictionaryClearByHand(PyObject *dict)
+{
+ // Clears the dictionary by hand:
+ // This prevents, extra references to global variables
+ // inside the GameLogic dictionary when the python interpreter is finalized.
+ // which allows the scene to safely delete them :)
+ // see: (space.c)->start_game
+ if(dict) PyDict_Clear(dict);
+}
+
+
+// Python Sandbox code
+// override builtin functions import() and open()
+
+
+PyObject *KXpy_open(PyObject *self, PyObject *args)
+{
+ PyErr_SetString(PyExc_RuntimeError, "Sandbox: open() function disabled!\nGame Scripts should not use this function.");
+ return NULL;
+}
+
+
+
+PyObject *KXpy_import(PyObject *self, PyObject *args)
+{
+ char *name;
+ PyObject *globals = NULL;
+ PyObject *locals = NULL;
+ PyObject *fromlist = NULL;
+ PyObject *l, *m, *n;
+
+ if (!PyArg_ParseTuple(args, "s|OOO:m_import",
+ &name, &globals, &locals, &fromlist))
+ return NULL;
+
+ /* check for builtin modules */
+ m = PyImport_AddModule("sys");
+ l = PyObject_GetAttrString(m, "builtin_module_names");
+ n = PyString_FromString(name);
+
+ if (PySequence_Contains(l, n)) {
+ return PyImport_ImportModuleEx(name, globals, locals, fromlist);
+ }
+
+ /* quick hack for GamePython modules
+ TODO: register builtin modules properly by ExtendInittab */
+ if (!strcmp(name, "GameLogic") || !strcmp(name, "GameKeys") || !strcmp(name, "PhysicsConstraints") ||
+ !strcmp(name, "Rasterizer")) {
+ return PyImport_ImportModuleEx(name, globals, locals, fromlist);
+ }
+
+ PyErr_Format(PyExc_ImportError,
+ "Import of external Module %.20s not allowed.", name);
+ return NULL;
+
+}
+
+
+
+static PyMethodDef meth_open[] = {
+ { "open", KXpy_open, METH_VARARGS,
+ "(disabled)"}
+};
+
+
+static PyMethodDef meth_import[] = {
+ { "import", KXpy_import, METH_VARARGS,
+ "our own import"}
+};
+
+
+
+//static PyObject *g_oldopen = 0;
+//static PyObject *g_oldimport = 0;
+//static int g_security = 0;
+
+
+void setSandbox(TPythonSecurityLevel level)
+{
+ PyObject *m = PyImport_AddModule("__builtin__");
+ PyObject *d = PyModule_GetDict(m);
+ PyObject *meth = PyCFunction_New(meth_open, NULL);
+
+ switch (level) {
+ case psl_Highest:
+ //if (!g_security) {
+ //g_oldopen = PyDict_GetItemString(d, "open");
+ PyDict_SetItemString(d, "open", meth);
+ meth = PyCFunction_New(meth_import, NULL);
+ PyDict_SetItemString(d, "__import__", meth);
+ //g_security = level;
+ //}
+ break;
+ /*
+ case psl_Lowest:
+ if (g_security) {
+ PyDict_SetItemString(d, "open", g_oldopen);
+ PyDict_SetItemString(d, "__import__", g_oldimport);
+ g_security = level;
+ }
+ */
+ default:
+ break;
+ }
+}
+
+/**
+ * Python is not initialised.
+ */
+PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level)
+{
+ STR_String pname = progname;
+ Py_SetProgramName(pname.Ptr());
+ Py_NoSiteFlag=1;
+ Py_FrozenFlag=1;
+ Py_Initialize();
+
+ //importBlenderModules()
+
+ setSandbox(level);
+
+ PyObject* moduleobj = PyImport_AddModule("__main__");
+ return PyModule_GetDict(moduleobj);
+}
+
+void exitGamePlayerPythonScripting()
+{
+ Py_Finalize();
+}
+
+/**
+ * Python is already initialized.
+ */
+PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level)
+{
+ STR_String pname = progname;
+ Py_SetProgramName(pname.Ptr());
+ Py_NoSiteFlag=1;
+ Py_FrozenFlag=1;
+
+ setSandbox(level);
+
+ PyObject* moduleobj = PyImport_AddModule("__main__");
+ return PyModule_GetDict(moduleobj);
+}
+
+
+
+void exitGamePythonScripting()
+{
+}
+
+
+
+PyObject* initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas)
+{
+ gp_Canvas = canvas;
+ gp_Rasterizer = rasty;
+
+
+ PyObject* m;
+ PyObject* d;
+
+ // Create the module and add the functions
+ m = Py_InitModule4("Rasterizer", rasterizer_methods,
+ Rasterizer_module_documentation,
+ (PyObject*)NULL,PYTHON_API_VERSION);
+
+ // Add some symbolic constants to the module
+ d = PyModule_GetDict(m);
+ ErrorObject = PyString_FromString("Rasterizer.error");
+ PyDict_SetItemString(d, "error", ErrorObject);
+
+ // XXXX Add constants here
+
+ // Check for errors
+ if (PyErr_Occurred())
+ {
+ Py_FatalError("can't initialize module Rasterizer");
+ }
+
+ return d;
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* GameKeys: symbolic constants for key mapping */
+/* ------------------------------------------------------------------------- */
+
+static char GameKeys_module_documentation[] =
+"This modules provides defines for key-codes"
+;
+
+
+
+static struct PyMethodDef gamekeys_methods[] = {
+ { NULL, (PyCFunction) NULL, 0, NULL }
+};
+
+
+
+PyObject* initGameKeys()
+{
+ PyObject* m;
+ PyObject* d;
+
+ // Create the module and add the functions
+ m = Py_InitModule4("GameKeys", gamekeys_methods,
+ GameKeys_module_documentation,
+ (PyObject*)NULL,PYTHON_API_VERSION);
+
+ // Add some symbolic constants to the module
+ d = PyModule_GetDict(m);
+
+ // XXXX Add constants here
+
+ KX_MACRO_addTypesToDict(d, AKEY, SCA_IInputDevice::KX_AKEY);
+ KX_MACRO_addTypesToDict(d, BKEY, SCA_IInputDevice::KX_BKEY);
+ KX_MACRO_addTypesToDict(d, CKEY, SCA_IInputDevice::KX_CKEY);
+ KX_MACRO_addTypesToDict(d, DKEY, SCA_IInputDevice::KX_DKEY);
+ KX_MACRO_addTypesToDict(d, EKEY, SCA_IInputDevice::KX_EKEY);
+ KX_MACRO_addTypesToDict(d, FKEY, SCA_IInputDevice::KX_FKEY);
+ KX_MACRO_addTypesToDict(d, GKEY, SCA_IInputDevice::KX_GKEY);
+ KX_MACRO_addTypesToDict(d, HKEY, SCA_IInputDevice::KX_HKEY);
+ KX_MACRO_addTypesToDict(d, IKEY, SCA_IInputDevice::KX_IKEY);
+ KX_MACRO_addTypesToDict(d, JKEY, SCA_IInputDevice::KX_JKEY);
+ KX_MACRO_addTypesToDict(d, KKEY, SCA_IInputDevice::KX_KKEY);
+ KX_MACRO_addTypesToDict(d, LKEY, SCA_IInputDevice::KX_LKEY);
+ KX_MACRO_addTypesToDict(d, MKEY, SCA_IInputDevice::KX_MKEY);
+ KX_MACRO_addTypesToDict(d, NKEY, SCA_IInputDevice::KX_NKEY);
+ KX_MACRO_addTypesToDict(d, OKEY, SCA_IInputDevice::KX_OKEY);
+ KX_MACRO_addTypesToDict(d, PKEY, SCA_IInputDevice::KX_PKEY);
+ KX_MACRO_addTypesToDict(d, QKEY, SCA_IInputDevice::KX_QKEY);
+ KX_MACRO_addTypesToDict(d, RKEY, SCA_IInputDevice::KX_RKEY);
+ KX_MACRO_addTypesToDict(d, SKEY, SCA_IInputDevice::KX_SKEY);
+ KX_MACRO_addTypesToDict(d, TKEY, SCA_IInputDevice::KX_TKEY);
+ KX_MACRO_addTypesToDict(d, UKEY, SCA_IInputDevice::KX_UKEY);
+ KX_MACRO_addTypesToDict(d, VKEY, SCA_IInputDevice::KX_VKEY);
+ KX_MACRO_addTypesToDict(d, WKEY, SCA_IInputDevice::KX_WKEY);
+ KX_MACRO_addTypesToDict(d, XKEY, SCA_IInputDevice::KX_XKEY);
+ KX_MACRO_addTypesToDict(d, YKEY, SCA_IInputDevice::KX_YKEY);
+ KX_MACRO_addTypesToDict(d, ZKEY, SCA_IInputDevice::KX_ZKEY);
+
+ KX_MACRO_addTypesToDict(d, ZEROKEY, SCA_IInputDevice::KX_ZEROKEY);
+ KX_MACRO_addTypesToDict(d, ONEKEY, SCA_IInputDevice::KX_ONEKEY);
+ KX_MACRO_addTypesToDict(d, TWOKEY, SCA_IInputDevice::KX_TWOKEY);
+ KX_MACRO_addTypesToDict(d, THREEKEY, SCA_IInputDevice::KX_THREEKEY);
+ KX_MACRO_addTypesToDict(d, FOURKEY, SCA_IInputDevice::KX_FOURKEY);
+ KX_MACRO_addTypesToDict(d, FIVEKEY, SCA_IInputDevice::KX_FIVEKEY);
+ KX_MACRO_addTypesToDict(d, SIXKEY, SCA_IInputDevice::KX_SIXKEY);
+ KX_MACRO_addTypesToDict(d, SEVENKEY, SCA_IInputDevice::KX_SEVENKEY);
+ KX_MACRO_addTypesToDict(d, EIGHTKEY, SCA_IInputDevice::KX_EIGHTKEY);
+ KX_MACRO_addTypesToDict(d, NINEKEY, SCA_IInputDevice::KX_NINEKEY);
+
+ KX_MACRO_addTypesToDict(d, CAPSLOCKKEY, SCA_IInputDevice::KX_CAPSLOCKKEY);
+
+ KX_MACRO_addTypesToDict(d, LEFTCTRLKEY, SCA_IInputDevice::KX_LEFTCTRLKEY);
+ KX_MACRO_addTypesToDict(d, LEFTALTKEY, SCA_IInputDevice::KX_LEFTALTKEY);
+ KX_MACRO_addTypesToDict(d, RIGHTALTKEY, SCA_IInputDevice::KX_RIGHTALTKEY);
+ KX_MACRO_addTypesToDict(d, RIGHTCTRLKEY, SCA_IInputDevice::KX_RIGHTCTRLKEY);
+ KX_MACRO_addTypesToDict(d, RIGHTSHIFTKEY, SCA_IInputDevice::KX_RIGHTSHIFTKEY);
+ KX_MACRO_addTypesToDict(d, LEFTSHIFTKEY, SCA_IInputDevice::KX_LEFTSHIFTKEY);
+
+ KX_MACRO_addTypesToDict(d, ESCKEY, SCA_IInputDevice::KX_ESCKEY);
+ KX_MACRO_addTypesToDict(d, TABKEY, SCA_IInputDevice::KX_TABKEY);
+ KX_MACRO_addTypesToDict(d, RETKEY, SCA_IInputDevice::KX_RETKEY);
+ KX_MACRO_addTypesToDict(d, SPACEKEY, SCA_IInputDevice::KX_SPACEKEY);
+ KX_MACRO_addTypesToDict(d, LINEFEEDKEY, SCA_IInputDevice::KX_LINEFEEDKEY);
+ KX_MACRO_addTypesToDict(d, BACKSPACEKEY, SCA_IInputDevice::KX_BACKSPACEKEY);
+ KX_MACRO_addTypesToDict(d, DELKEY, SCA_IInputDevice::KX_DELKEY);
+ KX_MACRO_addTypesToDict(d, SEMICOLONKEY, SCA_IInputDevice::KX_SEMICOLONKEY);
+ KX_MACRO_addTypesToDict(d, PERIODKEY, SCA_IInputDevice::KX_PERIODKEY);
+ KX_MACRO_addTypesToDict(d, COMMAKEY, SCA_IInputDevice::KX_COMMAKEY);
+ KX_MACRO_addTypesToDict(d, QUOTEKEY, SCA_IInputDevice::KX_QUOTEKEY);
+ KX_MACRO_addTypesToDict(d, ACCENTGRAVEKEY, SCA_IInputDevice::KX_ACCENTGRAVEKEY);
+ KX_MACRO_addTypesToDict(d, MINUSKEY, SCA_IInputDevice::KX_MINUSKEY);
+ KX_MACRO_addTypesToDict(d, SLASHKEY, SCA_IInputDevice::KX_SLASHKEY);
+ KX_MACRO_addTypesToDict(d, BACKSLASHKEY, SCA_IInputDevice::KX_BACKSLASHKEY);
+ KX_MACRO_addTypesToDict(d, EQUALKEY, SCA_IInputDevice::KX_EQUALKEY);
+ KX_MACRO_addTypesToDict(d, LEFTBRACKETKEY, SCA_IInputDevice::KX_LEFTBRACKETKEY);
+ KX_MACRO_addTypesToDict(d, RIGHTBRACKETKEY, SCA_IInputDevice::KX_RIGHTBRACKETKEY);
+
+ KX_MACRO_addTypesToDict(d, LEFTARROWKEY, SCA_IInputDevice::KX_LEFTARROWKEY);
+ KX_MACRO_addTypesToDict(d, DOWNARROWKEY, SCA_IInputDevice::KX_DOWNARROWKEY);
+ KX_MACRO_addTypesToDict(d, RIGHTARROWKEY, SCA_IInputDevice::KX_RIGHTARROWKEY);
+ KX_MACRO_addTypesToDict(d, UPARROWKEY, SCA_IInputDevice::KX_UPARROWKEY);
+
+ KX_MACRO_addTypesToDict(d, PAD2 , SCA_IInputDevice::KX_PAD2);
+ KX_MACRO_addTypesToDict(d, PAD4 , SCA_IInputDevice::KX_PAD4);
+ KX_MACRO_addTypesToDict(d, PAD6 , SCA_IInputDevice::KX_PAD6);
+ KX_MACRO_addTypesToDict(d, PAD8 , SCA_IInputDevice::KX_PAD8);
+
+ KX_MACRO_addTypesToDict(d, PAD1 , SCA_IInputDevice::KX_PAD1);
+ KX_MACRO_addTypesToDict(d, PAD3 , SCA_IInputDevice::KX_PAD3);
+ KX_MACRO_addTypesToDict(d, PAD5 , SCA_IInputDevice::KX_PAD5);
+ KX_MACRO_addTypesToDict(d, PAD7 , SCA_IInputDevice::KX_PAD7);
+ KX_MACRO_addTypesToDict(d, PAD9 , SCA_IInputDevice::KX_PAD9);
+
+ KX_MACRO_addTypesToDict(d, PADPERIOD, SCA_IInputDevice::KX_PADPERIOD);
+ KX_MACRO_addTypesToDict(d, PADSLASHKEY, SCA_IInputDevice::KX_PADSLASHKEY);
+ KX_MACRO_addTypesToDict(d, PADASTERKEY, SCA_IInputDevice::KX_PADASTERKEY);
+
+
+ KX_MACRO_addTypesToDict(d, PAD0, SCA_IInputDevice::KX_PAD0);
+ KX_MACRO_addTypesToDict(d, PADMINUS, SCA_IInputDevice::KX_PADMINUS);
+ KX_MACRO_addTypesToDict(d, PADENTER, SCA_IInputDevice::KX_PADENTER);
+ KX_MACRO_addTypesToDict(d, PADPLUSKEY, SCA_IInputDevice::KX_PADPLUSKEY);
+
+
+ KX_MACRO_addTypesToDict(d, F1KEY , SCA_IInputDevice::KX_F1KEY);
+ KX_MACRO_addTypesToDict(d, F2KEY , SCA_IInputDevice::KX_F2KEY);
+ KX_MACRO_addTypesToDict(d, F3KEY , SCA_IInputDevice::KX_F3KEY);
+ KX_MACRO_addTypesToDict(d, F4KEY , SCA_IInputDevice::KX_F4KEY);
+ KX_MACRO_addTypesToDict(d, F5KEY , SCA_IInputDevice::KX_F5KEY);
+ KX_MACRO_addTypesToDict(d, F6KEY , SCA_IInputDevice::KX_F6KEY);
+ KX_MACRO_addTypesToDict(d, F7KEY , SCA_IInputDevice::KX_F7KEY);
+ KX_MACRO_addTypesToDict(d, F8KEY , SCA_IInputDevice::KX_F8KEY);
+ KX_MACRO_addTypesToDict(d, F9KEY , SCA_IInputDevice::KX_F9KEY);
+ KX_MACRO_addTypesToDict(d, F10KEY, SCA_IInputDevice::KX_F10KEY);
+ KX_MACRO_addTypesToDict(d, F11KEY, SCA_IInputDevice::KX_F11KEY);
+ KX_MACRO_addTypesToDict(d, F12KEY, SCA_IInputDevice::KX_F12KEY);
+
+ KX_MACRO_addTypesToDict(d, PAUSEKEY, SCA_IInputDevice::KX_PAUSEKEY);
+ KX_MACRO_addTypesToDict(d, INSERTKEY, SCA_IInputDevice::KX_INSERTKEY);
+ KX_MACRO_addTypesToDict(d, HOMEKEY , SCA_IInputDevice::KX_HOMEKEY);
+ KX_MACRO_addTypesToDict(d, PAGEUPKEY, SCA_IInputDevice::KX_PAGEUPKEY);
+ KX_MACRO_addTypesToDict(d, PAGEDOWNKEY, SCA_IInputDevice::KX_PAGEDOWNKEY);
+ KX_MACRO_addTypesToDict(d, ENDKEY, SCA_IInputDevice::KX_ENDKEY);
+
+
+ // Check for errors
+ if (PyErr_Occurred())
+ {
+ Py_FatalError("can't initialize module GameKeys");
+ }
+
+ return d;
+}
+
+void PHY_SetActiveScene(class KX_Scene* scene)
+{
+ gp_KetsjiScene = scene;
+}
diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h
new file mode 100644
index 00000000000..a4c2d1453a6
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PythonInit.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 __KX_PYTHON_INIT
+#define __KX_PYTHON_INIT
+
+#include "KX_Python.h"
+#include "STR_String.h"
+
+typedef enum {
+ psl_Lowest = 0,
+ psl_Highest
+} TPythonSecurityLevel;
+
+extern bool gUseVisibilityTemp;
+
+
+PyObject* initGameLogic(class KX_Scene* ketsjiscene);
+PyObject* initGameKeys();
+PyObject* initRasterizer(class RAS_IRasterizer* rasty,class RAS_ICanvas* canvas);
+PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level);
+void exitGamePlayerPythonScripting();
+PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level);
+void exitGamePythonScripting();
+void dictionaryClearByHand(PyObject *dict);
+
+void PHY_SetActiveScene(class KX_Scene* scene);
+#include "MT_Vector3.h"
+
+void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color);
+
+#endif //__KX_PYTHON_INIT
+
diff --git a/source/gameengine/Ketsji/KX_RadarSensor.cpp b/source/gameengine/Ketsji/KX_RadarSensor.cpp
new file mode 100644
index 00000000000..5d56eaabb5a
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_RadarSensor.cpp
@@ -0,0 +1,259 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_RadarSensor.h"
+#include "KX_GameObject.h"
+#include "PHY_IPhysicsController.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/**
+ * RadarSensor constructor. Creates a near-sensor derived class, with a cone collision shape.
+ */
+KX_RadarSensor::KX_RadarSensor(SCA_EventManager* eventmgr,
+ KX_GameObject* gameobj,
+ PHY_IPhysicsController* physCtrl,
+ double coneradius,
+ double coneheight,
+ int axis,
+ double margin,
+ double resetmargin,
+ bool bFindMaterial,
+ const STR_String& touchedpropname,
+ class KX_Scene* kxscene,
+ PyTypeObject* T)
+
+ : KX_NearSensor(
+ eventmgr,
+ gameobj,
+ //DT_NewCone(coneradius,coneheight),
+ margin,
+ resetmargin,
+ bFindMaterial,
+ touchedpropname,
+ kxscene,
+ physCtrl,
+ T),
+ m_coneradius(coneradius),
+ m_coneheight(coneheight),
+ m_axis(axis)
+{
+ m_client_info->m_type = KX_ClientObjectInfo::RADAR;
+ //m_client_info->m_clientobject = gameobj;
+ //m_client_info->m_auxilary_info = NULL;
+ //sumoObj->setClientObject(&m_client_info);
+}
+
+
+KX_RadarSensor::~KX_RadarSensor()
+{
+
+}
+
+CValue* KX_RadarSensor::GetReplica()
+{
+ KX_RadarSensor* replica = new KX_RadarSensor(*this);
+ replica->m_colliders = new CListValue();
+ replica->m_bCollision = false;
+ replica->m_bTriggered= false;
+ replica->m_hitObject = NULL;
+ replica->m_bLastTriggered = false;
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ replica->m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::RADAR);
+
+ if (replica->m_physCtrl)
+ {
+ replica->m_physCtrl = replica->m_physCtrl->GetReplica();
+ }
+
+ //todo: make sure replication works fine!
+ //>m_sumoObj = new SM_Object(DT_NewCone(m_coneradius, m_coneheight),NULL,NULL,NULL);
+ //replica->m_sumoObj->setMargin(m_Margin);
+ //replica->m_sumoObj->setClientObject(replica->m_client_info);
+
+ ((KX_GameObject*)replica->GetParent())->GetSGNode()->ComputeWorldTransforms(NULL);
+ replica->SynchronizeTransform();
+
+ return replica;
+}
+
+
+/**
+ * Transforms the collision object. A cone is not correctly centered
+ * for usage. */
+void KX_RadarSensor::SynchronizeTransform()
+{
+ // Getting the parent location was commented out. Why?
+ MT_Transform trans;
+ trans.setOrigin(((KX_GameObject*)GetParent())->NodeGetWorldPosition());
+ trans.setBasis(((KX_GameObject*)GetParent())->NodeGetWorldOrientation());
+ // What is the default orientation? pointing in the -y direction?
+ // is the geometry correctly converted?
+
+ // a collision cone is oriented
+ // center the cone correctly
+ // depends on the radar 'axis'
+ switch (m_axis)
+ {
+ case 0: // X Axis
+ {
+ MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(90));
+ trans.rotate(rotquatje);
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0));
+ break;
+ };
+ case 1: // Y Axis
+ {
+ MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-180));
+ trans.rotate(rotquatje);
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0));
+ break;
+ };
+ case 2: // Z Axis
+ {
+ MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-90));
+ trans.rotate(rotquatje);
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0));
+ break;
+ };
+ default:
+ {
+ }
+ }
+ m_cone_origin = trans.getOrigin();
+ m_cone_target = trans(MT_Point3(0, -m_coneheight/2.0 ,0));
+
+
+ if (m_physCtrl)
+ {
+ m_physCtrl->setPosition(trans.getOrigin().x(),trans.getOrigin().y(),trans.getOrigin().z());
+ m_physCtrl->setOrientation(trans.getRotation().x(),trans.getRotation().y(),trans.getRotation().z(),trans.getRotation().w());
+ m_physCtrl->calcXform();
+ }
+
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_RadarSensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_RadarSensor",
+ sizeof(KX_RadarSensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_RadarSensor::Parents[] = {
+ &KX_RadarSensor::Type,
+ &KX_NearSensor::Type,
+ &KX_TouchSensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_RadarSensor::Methods[] = {
+ {"getConeOrigin", (PyCFunction) KX_RadarSensor::sPyGetConeOrigin,
+ METH_VARARGS, GetConeOrigin_doc},
+ {"getConeTarget", (PyCFunction) KX_RadarSensor::sPyGetConeTarget,
+ METH_VARARGS, GetConeTarget_doc},
+ {"getConeHeight", (PyCFunction) KX_RadarSensor::sPyGetConeHeight,
+ METH_VARARGS, GetConeHeight_doc},
+ {NULL,NULL,NULL,NULL} //Sentinel
+};
+
+PyObject* KX_RadarSensor::_getattr(const STR_String& attr) {
+ _getattr_up(KX_TouchSensor);
+}
+
+/* getConeOrigin */
+char KX_RadarSensor::GetConeOrigin_doc[] =
+"getConeOrigin()\n"
+"\tReturns the origin of the cone with which to test. The origin\n"
+"\tis in the middle of the cone.";
+PyObject* KX_RadarSensor::PyGetConeOrigin(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_cone_origin[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_cone_origin[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_cone_origin[2]));
+
+ return retVal;
+}
+
+/* getConeOrigin */
+char KX_RadarSensor::GetConeTarget_doc[] =
+"getConeTarget()\n"
+"\tReturns the center of the bottom face of the cone with which to test.\n";
+PyObject* KX_RadarSensor::PyGetConeTarget(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_cone_target[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_cone_target[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_cone_target[2]));
+
+ return retVal;
+}
+
+/* getConeOrigin */
+char KX_RadarSensor::GetConeHeight_doc[] =
+"getConeHeight()\n"
+"\tReturns the height of the cone with which to test.\n";
+PyObject* KX_RadarSensor::PyGetConeHeight(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return PyFloat_FromDouble(m_coneheight);
+}
+
+
diff --git a/source/gameengine/Ketsji/KX_RadarSensor.h b/source/gameengine/Ketsji/KX_RadarSensor.h
new file mode 100644
index 00000000000..4f5ff994b40
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_RadarSensor.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): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef __KX_RADAR_SENSOR_H
+#define __KX_RADAR_SENSOR_H
+
+#include "KX_NearSensor.h"
+#include "MT_Point3.h"
+
+/**
+* Radar 'cone' sensor. Very similar to a near-sensor, but instead of a sphere, a cone is used.
+*/
+class KX_RadarSensor : public KX_NearSensor
+{
+ protected:
+ Py_Header;
+
+ MT_Scalar m_coneradius;
+
+ /**
+ * Height of the cone.
+ */
+ MT_Scalar m_coneheight;
+ int m_axis;
+
+ /**
+ * The previous position of the origin of the cone.
+ */
+ MT_Point3 m_cone_origin;
+
+ /**
+ * The previous direction of the cone (origin to bottom plane).
+ */
+ MT_Point3 m_cone_target;
+
+public:
+
+ KX_RadarSensor(SCA_EventManager* eventmgr,
+ KX_GameObject* gameobj,
+ PHY_IPhysicsController* physCtrl,
+ double coneradius,
+ double coneheight,
+ int axis,
+ double margin,
+ double resetmargin,
+ bool bFindMaterial,
+ const STR_String& touchedpropname,
+ class KX_Scene* kxscene,
+ PyTypeObject* T = &Type);
+ KX_RadarSensor();
+ virtual ~KX_RadarSensor();
+ virtual void SynchronizeTransform();
+ virtual CValue* GetReplica();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ KX_PYMETHOD_DOC(KX_RadarSensor,GetConeOrigin);
+ KX_PYMETHOD_DOC(KX_RadarSensor,GetConeTarget);
+ KX_PYMETHOD_DOC(KX_RadarSensor,GetConeHeight);
+
+};
+
+#endif //__KX_RADAR_SENSOR_H
+
diff --git a/source/gameengine/Ketsji/KX_RayCast.cpp b/source/gameengine/Ketsji/KX_RayCast.cpp
new file mode 100644
index 00000000000..7b13cb1fd7d
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_RayCast.cpp
@@ -0,0 +1,101 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * KX_MouseFocusSensor determines mouse in/out/over events.
+ */
+
+#include <stdlib.h>
+
+#include "KX_RayCast.h"
+
+#include "MT_Point3.h"
+#include "MT_Vector3.h"
+
+#include "KX_IPhysicsController.h"
+#include "PHY_IPhysicsEnvironment.h"
+#include "PHY_IPhysicsController.h"
+
+bool KX_RayCast::RayTest(KX_IPhysicsController* ignore_controller, PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, MT_Point3& result_point, MT_Vector3& result_normal, const KX_RayCast& callback)
+{
+ // Loops over all physics objects between frompoint and topoint,
+ // calling callback.RayHit for each one.
+ //
+ // callback.RayHit should return true to stop looking, or false to continue.
+ //
+ // returns true if an object was found, false if not.
+ MT_Point3 frompoint(_frompoint);
+ const MT_Vector3 todir( (topoint - frompoint).normalized() );
+
+ PHY_IPhysicsController* hit_controller;
+ PHY__Vector3 phy_pos;
+ PHY__Vector3 phy_normal;
+
+ while((hit_controller = physics_environment->rayTest(dynamic_cast<PHY_IPhysicsController*>(ignore_controller),
+ frompoint.x(),frompoint.y(),frompoint.z(),
+ topoint.x(),topoint.y(),topoint.z(),
+ phy_pos[0],phy_pos[1],phy_pos[2],
+ phy_normal[0],phy_normal[1],phy_normal[2])))
+ {
+ result_point = MT_Point3(phy_pos);
+ result_normal = MT_Vector3(phy_normal);
+ KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(hit_controller->getNewClientInfo());
+
+ if (!info)
+ {
+ printf("no info!\n");
+ MT_assert(info && "Physics controller with no client object info");
+ return false;
+ }
+
+ if (callback.RayHit(info, result_point, result_normal))
+ return true;
+
+
+ // skip past the object and keep tracing
+ /* We add 0.01 of fudge, so that if the margin && radius == 0., we don't endless loop. */
+ MT_Scalar marg = 0.01 + hit_controller->GetMargin();
+ marg += 2.f * hit_controller->GetMargin();
+ /* Calculate the other side of this object */
+ PHY__Vector3 hitpos;
+ hit_controller->getPosition(hitpos);
+ MT_Point3 hitObjPos(hitpos);
+
+ MT_Vector3 hitvector = hitObjPos - result_point;
+ if (hitvector.dot(hitvector) > MT_EPSILON)
+ {
+ hitvector.normalize();
+ marg *= 2.*todir.dot(hitvector);
+ }
+ frompoint = result_point + marg * todir;
+ }
+
+ return hit_controller;
+}
+
diff --git a/source/gameengine/Ketsji/KX_RayCast.h b/source/gameengine/Ketsji/KX_RayCast.h
new file mode 100644
index 00000000000..8bb21e28aca
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_RayCast.h
@@ -0,0 +1,107 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_RAYCAST_H__
+#define __KX_RAYCAST_H__
+
+class MT_Point3;
+class MT_Vector3;
+class KX_IPhysicsController;
+class PHY_IPhysicsEnvironment;
+
+struct KX_ClientObjectInfo;
+
+/**
+ * Defines a function for doing a ray cast.
+ *
+ * eg KX_RayCast::RayTest(ignore_physics_controller, physics_environment, frompoint, topoint, result_point, result_normal, KX_RayCast::Callback<KX_MyClass>(this, data)
+ *
+ * Calls myclass->RayHit(client, hit_point, hit_normal, data) for all client
+ * between frompoint and topoint
+ *
+ * myclass->RayHit should return true to end the raycast, false to ignore the current client.
+ *
+ * Returns true if a client was accepted, false if nothing found.
+ */
+class KX_RayCast
+{
+protected:
+ KX_RayCast() {};
+public:
+ virtual ~KX_RayCast() {}
+
+ /** ray test callback.
+ * either override this in your class, or use a callback wrapper.
+ */
+ virtual bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal) const = 0;
+
+ /**
+ * Callback wrapper.
+ *
+ * Construct with KX_RayCast::Callback<MyClass>(this, data)
+ * and pass to KX_RayCast::RayTest
+ */
+ template<class T> class Callback;
+
+ /// Public interface.
+ /// Implement bool RayHit in your class to receive ray callbacks.
+ static bool RayTest(KX_IPhysicsController* physics_controller,
+ PHY_IPhysicsEnvironment* physics_environment,
+ const MT_Point3& _frompoint,
+ const MT_Point3& topoint,
+ MT_Point3& result_point,
+ MT_Vector3& result_normal,
+ const KX_RayCast& callback);
+
+};
+
+template<class T> class KX_RayCast::Callback : public KX_RayCast
+{
+ T *self;
+ void *data;
+public:
+ Callback(T *_self, void *_data = NULL)
+ : self(_self),
+ data(_data)
+ {
+ }
+
+ ~Callback() {}
+
+ virtual bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal) const
+ {
+ return self->RayHit(client, hit_point, hit_normal, data);
+ }
+};
+
+
+#endif
diff --git a/source/gameengine/Ketsji/KX_RayEventManager.cpp b/source/gameengine/Ketsji/KX_RayEventManager.cpp
new file mode 100644
index 00000000000..0fb1cee6446
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_RayEventManager.cpp
@@ -0,0 +1,60 @@
+/**
+ * Manager for ray events
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_RayEventManager.h"
+#include "SCA_LogicManager.h"
+#include "SCA_ISensor.h"
+#include <vector>
+
+using namespace std;
+
+#include <iostream>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void KX_RayEventManager::NextFrame()
+{
+ for (vector<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++)
+ {
+ SCA_ISensor *sensor = *i;
+ sensor->Activate(m_logicmgr, NULL);
+ }
+}
+
+void KX_RayEventManager::RegisterSensor(SCA_ISensor* sensor)
+{
+ m_sensors.push_back(sensor);
+};
diff --git a/source/gameengine/Ketsji/KX_RayEventManager.h b/source/gameengine/Ketsji/KX_RayEventManager.h
new file mode 100644
index 00000000000..8aa1ed990cd
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_RayEventManager.h
@@ -0,0 +1,55 @@
+/**
+ * Manager for ray events
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_RAYEVENTMGR
+#define __KX_RAYEVENTMGR
+#include "SCA_EventManager.h"
+#include <vector>
+using namespace std;
+
+class KX_RayEventManager : public SCA_EventManager
+{
+
+ class SCA_LogicManager* m_logicmgr;
+public:
+ KX_RayEventManager(class SCA_LogicManager* logicmgr)
+ : SCA_EventManager(RAY_EVENTMGR),
+ m_logicmgr(logicmgr)
+ {}
+ virtual void NextFrame();
+ virtual void RegisterSensor(SCA_ISensor* sensor);
+};
+
+#endif //__KX_RAYEVENTMGR
+
diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp
new file mode 100644
index 00000000000..ef3ec3e0be3
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_RaySensor.cpp
@@ -0,0 +1,392 @@
+/**
+ * Cast a ray and feel for objects
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_RaySensor.h"
+#include "SCA_EventManager.h"
+#include "SCA_RandomEventManager.h"
+#include "SCA_LogicManager.h"
+#include "SCA_IObject.h"
+#include "KX_ClientObjectInfo.h"
+#include "KX_GameObject.h"
+#include "KX_Scene.h"
+#include "KX_RayCast.h"
+#include "PHY_IPhysicsEnvironment.h"
+#include "KX_IPhysicsController.h"
+#include "PHY_IPhysicsController.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ const STR_String& propname,
+ bool bFindMaterial,
+ double distance,
+ int axis,
+ KX_Scene* ketsjiScene,
+ PyTypeObject* T)
+ : SCA_ISensor(gameobj,eventmgr, T),
+ m_propertyname(propname),
+ m_bFindMaterial(bFindMaterial),
+ m_distance(distance),
+ m_scene(ketsjiScene),
+ m_bTriggered(false),
+ m_axis(axis),
+ m_rayHit(false),
+ m_hitObject(NULL)
+
+
+{
+
+}
+
+
+
+KX_RaySensor::~KX_RaySensor()
+{
+ /* Nothing to be done here. */
+}
+
+
+
+CValue* KX_RaySensor::GetReplica()
+{
+ CValue* replica = new KX_RaySensor(*this);
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+bool KX_RaySensor::IsPositiveTrigger()
+{
+ bool result = m_rayHit;
+
+ if (m_invert)
+ result = !result;
+
+ return result;
+}
+
+bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data)
+{
+
+ KX_GameObject* hitKXObj = client->m_gameobject;
+
+ if (client->m_type > KX_ClientObjectInfo::ACTOR)
+ {
+ // false hit
+ return false;
+ }
+ bool bFound = false;
+
+ if (m_propertyname.Length() == 0)
+ {
+ bFound = true;
+ }
+ else
+ {
+ if (m_bFindMaterial)
+ {
+ if (client->m_auxilary_info)
+ {
+ bFound = (m_propertyname== ((char*)client->m_auxilary_info));
+ }
+ }
+ else
+ {
+ bFound = hitKXObj->GetProperty(m_propertyname) != NULL;
+ }
+ }
+
+ if (bFound)
+ {
+ m_rayHit = true;
+ m_hitObject = hitKXObj;
+ m_hitPosition = hit_point;
+ m_hitNormal = hit_normal;
+
+ }
+
+ return true;
+
+}
+
+
+
+bool KX_RaySensor::Evaluate(CValue* event)
+{
+ bool result = false;
+ m_rayHit = false;
+ m_hitObject = NULL;
+ m_hitPosition = MT_Vector3(0,0,0);
+ m_hitNormal = MT_Vector3(1,0,0);
+
+ KX_GameObject* obj = (KX_GameObject*)GetParent();
+ MT_Point3 frompoint = obj->NodeGetWorldPosition();
+ MT_Matrix3x3 matje = obj->NodeGetWorldOrientation();
+ MT_Matrix3x3 invmat = matje.inverse();
+
+ MT_Vector3 todir;
+ switch (m_axis)
+ {
+ case 1: // X
+ {
+ todir[0] = invmat[0][0];
+ todir[1] = invmat[0][1];
+ todir[2] = invmat[0][2];
+ break;
+ }
+ case 0: // Y
+ {
+ todir[0] = invmat[1][0];
+ todir[1] = invmat[1][1];
+ todir[2] = invmat[1][2];
+ break;
+ }
+ case 2: // Z
+ {
+ todir[0] = invmat[2][0];
+ todir[1] = invmat[2][1];
+ todir[2] = invmat[2][2];
+ break;
+ }
+ case 3: // -X
+ {
+ todir[0] = -invmat[0][0];
+ todir[1] = -invmat[0][1];
+ todir[2] = -invmat[0][2];
+ break;
+ }
+ case 4: // -Y
+ {
+ todir[0] = -invmat[1][0];
+ todir[1] = -invmat[1][1];
+ todir[2] = -invmat[1][2];
+ break;
+ }
+ case 5: // -Z
+ {
+ todir[0] = -invmat[2][0];
+ todir[1] = -invmat[2][1];
+ todir[2] = -invmat[2][2];
+ break;
+ }
+ }
+ todir.normalize();
+ m_rayDirection = todir;
+
+ MT_Point3 topoint = frompoint + (m_distance) * todir;
+ MT_Point3 resultpoint;
+ MT_Vector3 resultnormal;
+ PHY_IPhysicsEnvironment* pe = m_scene->GetPhysicsEnvironment();
+
+ if (!pe)
+ {
+ std::cout << "WARNING: Ray sensor " << GetName() << ": There is no physics environment!" << std::endl;
+ std::cout << " Check universe for malfunction." << std::endl;
+ return false;
+ }
+
+ KX_IPhysicsController *spc = obj->GetPhysicsController();
+ KX_GameObject *parent = obj->GetParent();
+ if (!spc && parent)
+ spc = parent->GetPhysicsController();
+
+ if (parent)
+ parent->Release();
+
+
+ PHY_IPhysicsEnvironment* physics_environment = this->m_scene->GetPhysicsEnvironment();
+
+
+ result = KX_RayCast::RayTest(spc, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_RaySensor>(this));
+
+ /* now pass this result to some controller */
+
+ if (m_rayHit)
+ {
+ if (!m_bTriggered)
+ {
+ // notify logicsystem that ray is now hitting
+ result = true;
+ m_bTriggered = true;
+ }
+ else
+ {
+ // notify logicsystem that ray is STILL hitting ...
+ result = false;
+
+ }
+ }
+ else
+ {
+ if (m_bTriggered)
+ {
+ m_bTriggered = false;
+ // notify logicsystem that ray JUST left the Object
+ result = true;
+ }
+
+ }
+
+
+ return result;
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_RaySensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_RaySensor",
+ sizeof(KX_RaySensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_RaySensor::Parents[] = {
+ &KX_RaySensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_RaySensor::Methods[] = {
+ {"getHitObject",(PyCFunction) KX_RaySensor::sPyGetHitObject,METH_VARARGS, GetHitObject_doc},
+ {"getHitPosition",(PyCFunction) KX_RaySensor::sPyGetHitPosition,METH_VARARGS, GetHitPosition_doc},
+ {"getHitNormal",(PyCFunction) KX_RaySensor::sPyGetHitNormal,METH_VARARGS, GetHitNormal_doc},
+ {"getRayDirection",(PyCFunction) KX_RaySensor::sPyGetRayDirection,METH_VARARGS, GetRayDirection_doc},
+ {NULL,NULL} //Sentinel
+};
+
+char KX_RaySensor::GetHitObject_doc[] =
+"getHitObject()\n"
+"\tReturns the name of the object that was hit by this ray.\n";
+PyObject* KX_RaySensor::PyGetHitObject(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ if (m_hitObject)
+ {
+ return m_hitObject->AddRef();
+ }
+ Py_Return;
+}
+
+
+char KX_RaySensor::GetHitPosition_doc[] =
+"getHitPosition()\n"
+"\tReturns the position (in worldcoordinates) where the object was hit by this ray.\n";
+PyObject* KX_RaySensor::PyGetHitPosition(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ MT_Point3 pos = m_hitPosition;
+
+ PyObject* resultlist = PyList_New(3);
+ int index;
+ for (index=0;index<3;index++)
+ {
+ PyList_SetItem(resultlist,index,PyFloat_FromDouble(pos[index]));
+ }
+ return resultlist;
+
+}
+
+char KX_RaySensor::GetRayDirection_doc[] =
+"getRayDirection()\n"
+"\tReturns the direction from the ray (in worldcoordinates) .\n";
+PyObject* KX_RaySensor::PyGetRayDirection(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ MT_Vector3 dir = m_rayDirection;
+
+ PyObject* resultlist = PyList_New(3);
+ int index;
+ for (index=0;index<3;index++)
+ {
+ PyList_SetItem(resultlist,index,PyFloat_FromDouble(dir[index]));
+ }
+ return resultlist;
+
+}
+
+char KX_RaySensor::GetHitNormal_doc[] =
+"getHitNormal()\n"
+"\tReturns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray.\n";
+PyObject* KX_RaySensor::PyGetHitNormal(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ MT_Vector3 pos = m_hitNormal;
+
+ PyObject* resultlist = PyList_New(3);
+ int index;
+ for (index=0;index<3;index++)
+ {
+ PyList_SetItem(resultlist,index,PyFloat_FromDouble(pos[index]));
+ }
+ return resultlist;
+
+}
+
+
+
+PyObject* KX_RaySensor::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_ISensor);
+}
diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h
new file mode 100644
index 00000000000..0e05c6021c0
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_RaySensor.h
@@ -0,0 +1,85 @@
+/**
+ * Cast a ray and feel for objects
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_RAYSENSOR_H
+#define __KX_RAYSENSOR_H
+
+#include "SCA_ISensor.h"
+#include "MT_Point3.h"
+
+struct KX_ClientObjectInfo;
+
+class KX_RaySensor : public SCA_ISensor
+{
+ Py_Header;
+ STR_String m_propertyname;
+ bool m_bFindMaterial;
+ double m_distance;
+ class KX_Scene* m_scene;
+ bool m_bTriggered;
+ int m_axis;
+ bool m_rayHit;
+ MT_Point3 m_hitPosition;
+ SCA_IObject* m_hitObject;
+ MT_Vector3 m_hitNormal;
+ MT_Vector3 m_rayDirection;
+
+public:
+ KX_RaySensor(class SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ const STR_String& propname,
+ bool fFindMaterial,
+ double distance,
+ int axis,
+ class KX_Scene* ketsjiScene,
+ PyTypeObject* T = &Type);
+ virtual ~KX_RaySensor();
+ virtual CValue* GetReplica();
+
+ virtual bool Evaluate(CValue* event);
+ virtual bool IsPositiveTrigger();
+
+ bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data);
+
+ KX_PYMETHOD_DOC(KX_RaySensor,GetHitObject);
+ KX_PYMETHOD_DOC(KX_RaySensor,GetHitPosition);
+ KX_PYMETHOD_DOC(KX_RaySensor,GetHitNormal);
+ KX_PYMETHOD_DOC(KX_RaySensor,GetRayDirection);
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+};
+
+#endif //__KX_RAYSENSOR_H
+
diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp
new file mode 100644
index 00000000000..45b2db10b33
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp
@@ -0,0 +1,361 @@
+//
+// Add an object when this actuator is triggered
+//
+// $Id$
+//
+// ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version. The Blender
+// Foundation also sells licenses for use in proprietary software under
+// the Blender License. See http://www.blender.org/BL/ for information
+// about this.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+// All rights reserved.
+//
+// The Original Code is: all of this file.
+//
+// Contributor(s): none yet.
+//
+// ***** END GPL/BL DUAL LICENSE BLOCK *****
+// Previously existed as:
+
+// \source\gameengine\GameLogic\SCA_AddObjectActuator.cpp
+
+// Please look here for revision history.
+
+
+#include "KX_SCA_AddObjectActuator.h"
+#include "SCA_IScene.h"
+#include "KX_GameObject.h"
+#include "KX_IPhysicsController.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+KX_SCA_AddObjectActuator::KX_SCA_AddObjectActuator(SCA_IObject *gameobj,
+ CValue* original,
+ int time,
+ SCA_IScene* scene,
+ const MT_Vector3& linvel,
+ bool local,
+ PyTypeObject* T)
+ :
+ SCA_IActuator(gameobj, T),
+ m_OriginalObject(original),
+ m_scene(scene),
+ m_linear_velocity(linvel),
+ m_localFlag(local)
+{
+ m_lastCreatedObject = NULL;
+ m_timeProp = time;
+}
+
+
+
+KX_SCA_AddObjectActuator::~KX_SCA_AddObjectActuator()
+{
+ if (m_lastCreatedObject)
+ m_lastCreatedObject->Release();
+}
+
+
+
+bool KX_SCA_AddObjectActuator::Update()
+{
+ //bool result = false; /*unused*/
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (bNegativeEvent) return false; // do nothing on negative events
+
+ InstantAddObject();
+
+
+ return false;
+}
+
+
+
+
+SCA_IObject* KX_SCA_AddObjectActuator::GetLastCreatedObject() const
+{
+ return m_lastCreatedObject;
+}
+
+
+
+CValue* KX_SCA_AddObjectActuator::GetReplica()
+{
+ KX_SCA_AddObjectActuator* replica = new KX_SCA_AddObjectActuator(*this);
+
+ if (replica == NULL)
+ return NULL;
+
+ // this will copy properties and so on...
+ replica->ProcessReplica();
+ replica->m_lastCreatedObject=NULL;
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_SCA_AddObjectActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_SCA_AddObjectActuator",
+ sizeof(KX_SCA_AddObjectActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0,
+ __repr,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_SCA_AddObjectActuator::Parents[] = {
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+PyMethodDef KX_SCA_AddObjectActuator::Methods[] = {
+ {"setObject", (PyCFunction) KX_SCA_AddObjectActuator::sPySetObject, METH_VARARGS, SetObject_doc},
+ {"setTime", (PyCFunction) KX_SCA_AddObjectActuator::sPySetTime, METH_VARARGS, SetTime_doc},
+ {"getObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetObject, METH_VARARGS, GetObject_doc},
+ {"getTime", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetTime, METH_VARARGS, GetTime_doc},
+ {"getLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLinearVelocity, METH_VARARGS, GetLinearVelocity_doc},
+ {"setLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPySetLinearVelocity, METH_VARARGS, SetLinearVelocity_doc},
+ {"getLastCreatedObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLastCreatedObject, METH_VARARGS,"getLastCreatedObject() : get the object handle to the last created object\n"},
+ {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_VARARGS,"instantAddObject() : immediately add object without delay\n"},
+
+ {NULL,NULL} //Sentinel
+};
+
+
+PyObject* KX_SCA_AddObjectActuator::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_IActuator);
+}
+
+/* 1. setObject */
+char KX_SCA_AddObjectActuator::SetObject_doc[] =
+"setObject(name)\n"
+"\t- name: string\n"
+"\tSets the object that will be added. There has to be an object\n"
+"\tof this name. If not, this function does nothing.\n";
+
+
+
+PyObject* KX_SCA_AddObjectActuator::PySetObject(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject* gameobj;
+ if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj))
+ {
+ m_OriginalObject = (CValue*)gameobj;
+ Py_Return;
+ }
+ PyErr_Clear();
+
+ char* objectname;
+ if (PyArg_ParseTuple(args, "s", &objectname))
+ {
+ m_OriginalObject= (CValue*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname));;
+
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+
+
+/* 2. setTime */
+char KX_SCA_AddObjectActuator::SetTime_doc[] =
+"setTime(duration)\n"
+"\t- duration: integer\n"
+"\tSets the lifetime of the object that will be added, in frames. \n"
+"\tIf the duration is negative, it is set to 0.\n";
+
+
+PyObject* KX_SCA_AddObjectActuator::PySetTime(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int deltatime;
+
+ if (!PyArg_ParseTuple(args, "i", &deltatime))
+ return NULL;
+
+ m_timeProp = deltatime;
+ if (m_timeProp < 0) m_timeProp = 0;
+
+ Py_Return;
+}
+
+
+
+/* 3. getTime */
+char KX_SCA_AddObjectActuator::GetTime_doc[] =
+"GetTime()\n"
+"\tReturns the lifetime of the object that will be added.\n";
+
+
+PyObject* KX_SCA_AddObjectActuator::PyGetTime(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyInt_FromLong(m_timeProp);
+}
+
+
+/* 4. getObject */
+char KX_SCA_AddObjectActuator::GetObject_doc[] =
+"getObject()\n"
+"\tReturns the name of the object that will be added.\n";
+
+
+
+PyObject* KX_SCA_AddObjectActuator::PyGetObject(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ if (!m_OriginalObject)
+ Py_Return;
+
+ return PyString_FromString(m_OriginalObject->GetName());
+}
+
+
+
+/* 5. getLinearVelocity */
+char KX_SCA_AddObjectActuator::GetLinearVelocity_doc[] =
+"GetLinearVelocity()\n"
+"\tReturns the linear velocity that will be assigned to \n"
+"\tthe created object.\n";
+
+
+
+PyObject* KX_SCA_AddObjectActuator::PyGetLinearVelocity(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2]));
+
+ return retVal;
+}
+
+
+
+/* 6. setLinearVelocity */
+char KX_SCA_AddObjectActuator::SetLinearVelocity_doc[] =
+"setLinearVelocity(vx, vy, vz)\n"
+"\t- vx: float\n"
+"\t- vy: float\n"
+"\t- vz: float\n"
+"\tAssign this velocity to the created object. \n";
+
+
+PyObject* KX_SCA_AddObjectActuator::PySetLinearVelocity(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ float vecArg[3];
+ if (!PyArg_ParseTuple(args, "fff", &vecArg[0], &vecArg[1], &vecArg[2]))
+ return NULL;
+
+ m_linear_velocity.setValue(vecArg);
+ Py_Return;
+}
+
+void KX_SCA_AddObjectActuator::InstantAddObject()
+{
+ if (m_OriginalObject)
+ {
+ // Add an identical object, with properties inherited from the original object
+ // Now it needs to be added to the current scene.
+ SCA_IObject* replica = m_scene->AddReplicaObject(m_OriginalObject,GetParent(),m_timeProp );
+ KX_GameObject * game_obj = static_cast<KX_GameObject *>(replica);
+ game_obj->setLinearVelocity(m_linear_velocity,m_localFlag);
+ game_obj->ResolveCombinedVelocities(m_linear_velocity, MT_Vector3(0., 0., 0.), m_localFlag, false);
+
+ // keep a copy of the last object, to allow python scripters to change it
+ if (m_lastCreatedObject)
+ {
+ //careful with destruction, it might still have outstanding collision callbacks
+ m_scene->DelayedReleaseObject(m_lastCreatedObject);
+ m_lastCreatedObject->Release();
+ }
+
+ m_lastCreatedObject = replica;
+ m_lastCreatedObject->AddRef();
+ }
+}
+
+PyObject* KX_SCA_AddObjectActuator::PyInstantAddObject(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ InstantAddObject();
+
+ Py_Return;
+}
+
+
+
+/* 7. GetLastCreatedObject */
+char KX_SCA_AddObjectActuator::GetLastCreatedObject_doc[] =
+"getLastCreatedObject()\n"
+"\tReturn the last created object. \n";
+
+
+PyObject* KX_SCA_AddObjectActuator::PyGetLastCreatedObject(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ SCA_IObject* result = this->GetLastCreatedObject();
+ if (result)
+ {
+ result->AddRef();
+ return result;
+ }
+ // don't return NULL to python anymore, it gives trouble in the scripts
+ Py_Return;
+}
diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h
new file mode 100644
index 00000000000..60adcb27b12
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h
@@ -0,0 +1,130 @@
+//
+// Add object to the game world on action of this actuator. A copy is made
+// of a referenced object. The copy inherits some properties from the owner
+// of this actuator.
+//
+// $Id$
+//
+// ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version. The Blender
+// Foundation also sells licenses for use in proprietary software under
+// the Blender License. See http://www.blender.org/BL/ for information
+// about this.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+// All rights reserved.
+//
+// The Original Code is: all of this file.
+//
+// Contributor(s): none yet.
+//
+// ***** END GPL/BL DUAL LICENSE BLOCK *****
+//
+// Previously existed as:
+// \source\gameengine\GameLogic\SCA_AddObjectActuator.h
+// Please look here for revision history.
+
+#ifndef __KX_SCA_AddObjectActuator
+#define __KX_SCA_AddObjectActuator
+
+/* Actuator tree */
+#include "SCA_IActuator.h"
+#include "SCA_LogicManager.h"
+
+#include "MT_Vector3.h"
+
+class SCA_IScene;
+
+class KX_SCA_AddObjectActuator : public SCA_IActuator
+{
+ Py_Header;
+
+ /// Time field: lifetime of the new object
+ int m_timeProp;
+
+ /// Original object reference (object to replicate)
+ CValue* m_OriginalObject;
+
+ /// Object will be added to the following scene
+ SCA_IScene* m_scene;
+
+ /// Linear velocity upon creation of the object.
+ MT_Vector3 m_linear_velocity;
+
+ /// Apply the velocity locally
+ bool m_localFlag;
+
+ SCA_IObject* m_lastCreatedObject;
+
+public:
+
+ /**
+ * This class also has the default constructors
+ * available. Use with care!
+ */
+
+ KX_SCA_AddObjectActuator(
+ SCA_IObject *gameobj,
+ CValue* original,
+ int time,
+ SCA_IScene* scene,
+ const MT_Vector3& linvel,
+ bool local,
+ PyTypeObject* T=&Type
+ );
+
+ ~KX_SCA_AddObjectActuator(void);
+
+ CValue*
+ GetReplica(
+ ) ;
+
+ virtual bool
+ Update();
+
+ virtual PyObject*
+ _getattr(
+ const STR_String& attr
+ );
+
+ SCA_IObject*
+ GetLastCreatedObject(
+ ) const ;
+
+ void InstantAddObject();
+
+ /* 1. setObject */
+ KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,SetObject);
+ /* 2. setTime */
+ KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,SetTime);
+ /* 3. getTime */
+ KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetTime);
+ /* 4. getObject */
+ KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetObject);
+ /* 5. getLinearVelocity */
+ KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetLinearVelocity);
+ /* 6. setLinearVelocity */
+ KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,SetLinearVelocity);
+ /* 7. getLastCreatedObject */
+ KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetLastCreatedObject);
+ /* 8. instantAddObject*/
+ KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,InstantAddObject);
+
+
+}; /* end of class KX_SCA_AddObjectActuator : public KX_EditObjectActuator */
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp
new file mode 100644
index 00000000000..1df1ad1f27a
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp
@@ -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 *****
+ */
+
+//
+
+// Remove the actuator's parent when triggered
+//
+// Previously existed as:
+// \source\gameengine\GameLogic\SCA_EndObjectActuator.cpp
+// Please look here for revision history.
+
+#include "SCA_IActuator.h"
+#include "KX_SCA_EndObjectActuator.h"
+#include "SCA_IScene.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_SCA_EndObjectActuator::KX_SCA_EndObjectActuator(SCA_IObject *gameobj,
+ SCA_IScene* scene,
+ PyTypeObject* T):
+ SCA_IActuator(gameobj, T),
+ m_scene(scene)
+{
+ // intentionally empty
+} /* End of constructor */
+
+
+
+KX_SCA_EndObjectActuator::~KX_SCA_EndObjectActuator()
+{
+ // there's nothing to be done here, really....
+} /* end of destructor */
+
+
+
+bool KX_SCA_EndObjectActuator::Update()
+{
+ // bool result = false; /*unused*/
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (bNegativeEvent)
+ return false; // do nothing on negative events
+ m_scene->DelayedRemoveObject(GetParent());
+
+ return false;
+}
+
+
+
+CValue* KX_SCA_EndObjectActuator::GetReplica()
+{
+ KX_SCA_EndObjectActuator* replica =
+ new KX_SCA_EndObjectActuator(*this);
+ if (replica == NULL) return NULL;
+
+ replica->ProcessReplica();
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+};
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions : integration hooks */
+/* ------------------------------------------------------------------------- */
+
+PyTypeObject KX_SCA_EndObjectActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_SCA_EndObjectActuator",
+ sizeof(KX_SCA_EndObjectActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+PyParentObject KX_SCA_EndObjectActuator::Parents[] = {
+ &KX_SCA_EndObjectActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+PyMethodDef KX_SCA_EndObjectActuator::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+
+PyObject* KX_SCA_EndObjectActuator::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_IActuator);
+}
+
+/* eof */
diff --git a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h
new file mode 100644
index 00000000000..ca77d80027d
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h
@@ -0,0 +1,78 @@
+//
+// Add object to the game world on action of this actuator
+//
+// $Id$
+//
+// ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version. The Blender
+// Foundation also sells licenses for use in proprietary software under
+// the Blender License. See http://www.blender.org/BL/ for information
+// about this.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+// All rights reserved.
+//
+// The Original Code is: all of this file.
+//
+// Contributor(s): none yet.
+//
+// ***** END GPL/BL DUAL LICENSE BLOCK *****
+//
+// Previously existed as:
+// \source\gameengine\GameLogic\SCA_EndObjectActuator.h
+// Please look here for revision history.
+
+#ifndef __KX_SCA_ENDOBJECTACTUATOR
+#define __KX_SCA_ENDOBJECTACTUATOR
+
+#include "SCA_IActuator.h"
+
+class SCA_IScene;
+
+class KX_SCA_EndObjectActuator : public SCA_IActuator
+{
+ Py_Header;
+ SCA_IScene* m_scene;
+
+ public:
+ KX_SCA_EndObjectActuator(
+ SCA_IObject* gameobj,
+ SCA_IScene* scene,
+ PyTypeObject* T=&Type
+ );
+
+ ~KX_SCA_EndObjectActuator();
+
+ CValue*
+ GetReplica(
+ );
+
+ virtual bool
+ Update();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject*
+ _getattr(
+ const STR_String& attr
+ );
+
+}; /* end of class KX_EditObjectActuator : public SCA_PropertyActuator */
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp
new file mode 100644
index 00000000000..221d531a1c2
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp
@@ -0,0 +1,209 @@
+//
+// Replace the mesh for this actuator's parent
+//
+// $Id$
+//
+// ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version. The Blender
+// Foundation also sells licenses for use in proprietary software under
+// the Blender License. See http://www.blender.org/BL/ for information
+// about this.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+// All rights reserved.
+//
+// The Original Code is: all of this file.
+//
+// Contributor(s): none yet.
+//
+// ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+//
+// Previously existed as:
+
+// \source\gameengine\GameLogic\SCA_ReplaceMeshActuator.cpp
+
+// Please look here for revision history.
+
+#include "KX_SCA_ReplaceMeshActuator.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+
+ PyTypeObject
+
+KX_SCA_ReplaceMeshActuator::
+
+Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_SCA_ReplaceMeshActuator",
+ sizeof(KX_SCA_ReplaceMeshActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0,
+ __repr,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_SCA_ReplaceMeshActuator::Parents[] = {
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+PyMethodDef KX_SCA_ReplaceMeshActuator::Methods[] = {
+ {"setMesh", (PyCFunction) KX_SCA_ReplaceMeshActuator::sPySetMesh, METH_VARARGS, SetMesh_doc},
+
+ KX_PYMETHODTABLE(KX_SCA_ReplaceMeshActuator, instantReplaceMesh),
+ KX_PYMETHODTABLE(KX_SCA_ReplaceMeshActuator, getMesh),
+ {NULL,NULL} //Sentinel
+};
+
+
+
+PyObject* KX_SCA_ReplaceMeshActuator::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_IActuator);
+}
+
+
+
+/* 1. setMesh */
+char KX_SCA_ReplaceMeshActuator::SetMesh_doc[] =
+ "setMesh(name)\n"
+ "\t- name: string\n"
+ "\tSet the mesh that will be substituted for the current one.\n";
+
+PyObject* KX_SCA_ReplaceMeshActuator::PySetMesh(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ char* meshname;
+
+ if (!PyArg_ParseTuple(args, "s", &meshname))
+ {
+ return NULL;
+ }
+
+ void* mesh = SCA_ILogicBrick::m_sCurrentLogicManager->GetMeshByName(STR_String(meshname));
+
+ if (mesh) {
+ m_mesh= (class RAS_MeshObject*)mesh;
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, getMesh,
+"getMesh() -> string\n"
+"Returns the name of the mesh to be substituted.\n"
+)
+{
+ if (!m_mesh)
+ Py_Return;
+
+ return PyString_FromString(const_cast<char *>(m_mesh->GetName().ReadPtr()));
+}
+
+
+KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, instantReplaceMesh,
+"instantReplaceMesh() : immediately replace mesh without delay\n")
+{
+ InstantReplaceMesh();
+ Py_Return;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+KX_SCA_ReplaceMeshActuator::KX_SCA_ReplaceMeshActuator(SCA_IObject *gameobj,
+ class RAS_MeshObject *mesh,
+ SCA_IScene* scene,
+ PyTypeObject* T) :
+
+ SCA_IActuator(gameobj, T),
+ m_mesh(mesh),
+ m_scene(scene)
+{
+} /* End of constructor */
+
+
+
+KX_SCA_ReplaceMeshActuator::~KX_SCA_ReplaceMeshActuator()
+{
+ // there's nothing to be done here, really....
+} /* end of destructor */
+
+
+
+bool KX_SCA_ReplaceMeshActuator::Update()
+{
+ // bool result = false; /*unused*/
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (bNegativeEvent)
+ return false; // do nothing on negative events
+
+ if (m_mesh) m_scene->ReplaceMesh(GetParent(),m_mesh);
+
+ return false;
+}
+
+
+
+CValue* KX_SCA_ReplaceMeshActuator::GetReplica()
+{
+ KX_SCA_ReplaceMeshActuator* replica =
+ new KX_SCA_ReplaceMeshActuator(*this);
+
+ if (replica == NULL)
+ return NULL;
+
+ replica->ProcessReplica();
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+};
+
+void KX_SCA_ReplaceMeshActuator::InstantReplaceMesh()
+{
+ if (m_mesh) m_scene->ReplaceMesh(GetParent(),m_mesh);
+}
+
+/* eof */
diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h
new file mode 100644
index 00000000000..339fce54c49
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h
@@ -0,0 +1,89 @@
+//
+// Add object to the game world on action of this actuator
+//
+// $Id$
+//
+// ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version. The Blender
+// Foundation also sells licenses for use in proprietary software under
+// the Blender License. See http://www.blender.org/BL/ for information
+// about this.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+// All rights reserved.
+//
+// The Original Code is: all of this file.
+//
+// Contributor(s): none yet.
+//
+// ***** END GPL/BL DUAL LICENSE BLOCK *****
+//
+// Previously existed as:
+// \source\gameengine\GameLogic\SCA_ReplaceMeshActuator.h
+// Please look here for revision history.
+//
+
+#ifndef __KX_SCA_REPLACEMESHACTUATOR
+#define __KX_SCA_REPLACEMESHACTUATOR
+
+#include "SCA_IActuator.h"
+#include "SCA_PropertyActuator.h"
+#include "SCA_LogicManager.h"
+#include "SCA_IScene.h"
+
+#include "RAS_MeshObject.h"
+
+class KX_SCA_ReplaceMeshActuator : public SCA_IActuator
+{
+ Py_Header;
+
+ // mesh reference (mesh to replace)
+ RAS_MeshObject* m_mesh;
+ SCA_IScene* m_scene;
+
+ public:
+ KX_SCA_ReplaceMeshActuator(
+ SCA_IObject* gameobj,
+ RAS_MeshObject *mesh,
+ SCA_IScene* scene,
+ PyTypeObject* T=&Type
+ );
+
+ ~KX_SCA_ReplaceMeshActuator(
+ );
+
+ CValue*
+ GetReplica(
+ );
+
+ virtual bool
+ Update();
+
+ virtual PyObject*
+ _getattr(
+ const STR_String& attr
+ );
+ void InstantReplaceMesh();
+
+ /* 1. setMesh */
+ KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,SetMesh);
+ KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,getMesh);
+ KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,instantReplaceMesh);
+
+};
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp
new file mode 100644
index 00000000000..632cb753240
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp
@@ -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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <iostream>
+
+#include "KX_SG_BoneParentNodeRelationship.h"
+
+#include "MT_Matrix4x4.h"
+#include "BL_ArmatureObject.h"
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/**
+ * Implementation of classes defined in KX_SG_BoneParentNodeRelationship.h
+ */
+
+/**
+ * first of all KX_SG_BoneParentRelation
+ */
+
+ KX_BoneParentRelation *
+KX_BoneParentRelation::
+New(Bone* bone
+) {
+ return new KX_BoneParentRelation(bone);
+}
+
+ bool
+KX_BoneParentRelation::
+UpdateChildCoordinates(
+ SG_Spatial * child,
+ const SG_Spatial * parent
+){
+ MT_assert(child != NULL);
+
+ // This way of accessing child coordinates is a bit cumbersome
+ // be nice to have non constant reference access to these values.
+
+ const MT_Vector3 & child_scale = child->GetLocalScale();
+ const MT_Point3 & child_pos = child->GetLocalPosition();
+ const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation();
+
+ // the childs world locations which we will update.
+
+ MT_Vector3 child_w_scale;
+ MT_Point3 child_w_pos;
+ MT_Matrix3x3 child_w_rotation;
+
+ bool valid_parent_transform = false;
+
+ if (parent)
+ {
+ const BL_ArmatureObject *armature = (const BL_ArmatureObject*)(parent->GetSGClientObject());
+ if (armature)
+ {
+ MT_Matrix4x4 parent_matrix;
+ if (armature->GetBoneMatrix(m_bone, parent_matrix))
+ {
+ // Get the child's transform, and the bone matrix.
+ MT_Matrix4x4 child_transform (
+ MT_Transform(child_pos + MT_Vector3(0.0, armature->GetBoneLength(m_bone), 0.0),
+ child_rotation.scaled(
+ child_scale[0],
+ child_scale[1],
+ child_scale[2])));
+
+ // The child's world transform is parent * child
+ parent_matrix = parent->GetWorldTransform() * parent_matrix;
+ child_transform = parent_matrix * child_transform;
+
+ // Recompute the child transform components from the transform.
+ child_w_scale = MT_Vector3(
+ MT_Vector3(child_transform[0][0], child_transform[0][1], child_transform[0][2]).length(),
+ MT_Vector3(child_transform[1][0], child_transform[1][1], child_transform[1][2]).length(),
+ MT_Vector3(child_transform[2][0], child_transform[2][1], child_transform[2][2]).length());
+ child_w_rotation = MT_Matrix3x3(child_transform[0][0], child_transform[0][1], child_transform[0][2],
+ child_transform[1][0], child_transform[1][1], child_transform[1][2],
+ child_transform[2][0], child_transform[2][1], child_transform[2][2]);
+ child_w_rotation.scale(1.0/child_w_scale[0], 1.0/child_w_scale[1], 1.0/child_w_scale[2]);
+
+ child_w_pos = MT_Point3(child_transform[0][3], child_transform[1][3], child_transform[2][3]);
+
+ valid_parent_transform = true;
+ }
+ }
+ }
+
+ if (!valid_parent_transform)
+ {
+ child_w_scale = child_scale;
+ child_w_pos = child_pos;
+ child_w_rotation = child_rotation;
+ }
+
+ child->SetWorldScale(child_w_scale);
+ child->SetWorldPosition(child_w_pos);
+ child->SetWorldOrientation(child_w_rotation);
+
+ return valid_parent_transform;
+}
+
+ SG_ParentRelation *
+KX_BoneParentRelation::
+NewCopy(
+){
+ KX_BoneParentRelation* bone_parent = new KX_BoneParentRelation(m_bone);
+ return bone_parent;
+}
+
+KX_BoneParentRelation::
+~KX_BoneParentRelation(
+){
+ //nothing to do
+}
+
+
+KX_BoneParentRelation::
+KX_BoneParentRelation(Bone* bone
+)
+: m_bone(bone)
+{
+ // nothing to do
+}
diff --git a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h
new file mode 100644
index 00000000000..1f816726264
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h
@@ -0,0 +1,109 @@
+/**
+ * @mainpage KX_SG_NodeRelationships
+
+ * @section
+ *
+ * This file provides common concrete implementations of
+ * SG_ParentRelation used by the game engine. These are
+ * KX_SlowParentRelation a slow parent relationship.
+ * KX_NormalParentRelation a normal parent relationship where
+ * orientation and position are inherited from the parent by
+ * the child.
+ * KX_VertexParentRelation only location information is
+ * inherited by the child.
+ *
+ * @see SG_ParentRelation for more information about this
+ * 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 __KX_SG_BONEPARENTRELATION_H__
+#define __KX_SG_BONEPARENTRELATION_H__
+
+#include "SG_Spatial.h"
+#include "SG_ParentRelation.h"
+
+struct Bone;
+
+/**
+ * Bone parent relationship parents a child SG_Spatial frame to a
+ * bone in an armature object.
+ */
+class KX_BoneParentRelation : public SG_ParentRelation
+{
+
+public :
+
+ /**
+ * Allocate and construct a new KX_SG_BoneParentRelation
+ * on the heap.
+ *
+ * bone is the bone id to use. Currently it is a pointer
+ * to a Blender struct Bone - this should be fixed if
+ */
+
+ static
+ KX_BoneParentRelation *
+ New(Bone* bone
+ );
+
+ /**
+ * Updates the childs world coordinates relative to the parent's
+ * world coordinates.
+ *
+ * Parent should be a BL_ArmatureObject.
+ */
+ bool
+ UpdateChildCoordinates(
+ SG_Spatial * child,
+ const SG_Spatial * parent
+ );
+
+ /**
+ * Create a copy of this relationship
+ */
+ SG_ParentRelation *
+ NewCopy(
+ );
+
+ ~KX_BoneParentRelation(
+ );
+
+private :
+ Bone* m_bone;
+ KX_BoneParentRelation(Bone* bone
+ );
+
+};
+
+#endif
diff --git a/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp b/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp
new file mode 100644
index 00000000000..540e14d06ea
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp
@@ -0,0 +1,339 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_SG_NodeRelationships.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/**
+ * Implementation of classes defined in KX_SG_NodeRelationships.h
+ */
+
+/**
+ * first of all KX_NormalParentRelation
+ */
+
+ KX_NormalParentRelation *
+KX_NormalParentRelation::
+New(
+) {
+ return new KX_NormalParentRelation();
+}
+
+ bool
+KX_NormalParentRelation::
+UpdateChildCoordinates(
+ SG_Spatial * child,
+ const SG_Spatial * parent
+){
+ MT_assert(child != NULL);
+
+ // This way of accessing child coordinates is a bit cumbersome
+ // be nice to have non constant reference access to these values.
+
+ const MT_Vector3 & child_scale = child->GetLocalScale();
+ const MT_Point3 & child_pos = child->GetLocalPosition();
+ const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation();
+
+ // the childs world locations which we will update.
+
+ MT_Vector3 child_w_scale;
+ MT_Point3 child_w_pos;
+ MT_Matrix3x3 child_w_rotation;
+
+ if (parent) {
+
+ const MT_Vector3 & p_world_scale = parent->GetWorldScaling();
+ const MT_Point3 & p_world_pos = parent->GetWorldPosition();
+ const MT_Matrix3x3 & p_world_rotation = parent->GetWorldOrientation();
+
+ child_w_scale = p_world_scale * child_scale;
+ child_w_rotation = p_world_rotation * child_rotation;
+
+ child_w_pos = p_world_pos + p_world_scale *
+ (p_world_rotation * child_pos);
+
+ } else {
+
+ child_w_scale = child_scale;
+ child_w_pos = child_pos;
+ child_w_rotation = child_rotation;
+ }
+
+ child->SetWorldScale(child_w_scale);
+ child->SetWorldPosition(child_w_pos);
+ child->SetWorldOrientation(child_w_rotation);
+
+ return parent != NULL;
+}
+
+ SG_ParentRelation *
+KX_NormalParentRelation::
+NewCopy(
+){
+ return new KX_NormalParentRelation();
+}
+
+KX_NormalParentRelation::
+~KX_NormalParentRelation(
+){
+ //nothing to do
+}
+
+
+KX_NormalParentRelation::
+KX_NormalParentRelation(
+){
+ // nothing to do
+}
+
+/**
+ * Next KX_VertexParentRelation
+ */
+
+
+ KX_VertexParentRelation *
+KX_VertexParentRelation::
+New(
+){
+ return new KX_VertexParentRelation();
+}
+
+/**
+ * Method inherited from KX_ParentRelation
+ */
+
+ bool
+KX_VertexParentRelation::
+UpdateChildCoordinates(
+ SG_Spatial * child,
+ const SG_Spatial * parent
+){
+
+ MT_assert(child != NULL);
+
+ const MT_Vector3 & child_scale = child->GetLocalScale();
+ const MT_Point3 & child_pos = child->GetLocalPosition();
+ const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation();
+
+ // the childs world locations which we will update.
+
+ MT_Vector3 child_w_scale;
+ MT_Point3 child_w_pos;
+ MT_Matrix3x3 child_w_rotation;
+
+ if (parent) {
+
+ // This is a vertex parent so we do not inherit orientation
+ // information.
+
+ // const MT_Vector3 & p_world_scale = parent->GetWorldScaling(); /*unused*/
+ const MT_Point3 & p_world_pos = parent->GetWorldPosition();
+ // const MT_Matrix3x3 & p_world_rotation = parent->GetWorldOrientation(); /*unused*/
+
+ child_w_scale = child_scale;
+ child_w_rotation = child_rotation;
+ child_w_pos = p_world_pos + child_pos;
+ } else {
+
+ child_w_scale = child_scale;
+ child_w_pos = child_pos;
+ child_w_rotation = child_rotation;
+ }
+
+ child->SetWorldScale(child_w_scale);
+ child->SetWorldPosition(child_w_pos);
+ child->SetWorldOrientation(child_w_rotation);
+
+ return parent != NULL;
+}
+
+/**
+ * Method inherited from KX_ParentRelation
+ */
+
+ SG_ParentRelation *
+KX_VertexParentRelation::
+NewCopy(
+){
+ return new KX_VertexParentRelation();
+};
+
+KX_VertexParentRelation::
+~KX_VertexParentRelation(
+){
+ //nothing to do
+}
+
+
+KX_VertexParentRelation::
+KX_VertexParentRelation(
+){
+ //nothing to do
+}
+
+
+/**
+ * Slow parent relationship
+ */
+
+ KX_SlowParentRelation *
+KX_SlowParentRelation::
+New(
+ MT_Scalar relaxation
+){
+ return new KX_SlowParentRelation(relaxation);
+}
+
+/**
+ * Method inherited from KX_ParentRelation
+ */
+
+ bool
+KX_SlowParentRelation::
+UpdateChildCoordinates(
+ SG_Spatial * child,
+ const SG_Spatial * parent
+){
+ MT_assert(child != NULL);
+
+ const MT_Vector3 & child_scale = child->GetLocalScale();
+ const MT_Point3 & child_pos = child->GetLocalPosition();
+ const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation();
+
+ // the childs world locations which we will update.
+
+ MT_Vector3 child_w_scale;
+ MT_Point3 child_w_pos;
+ MT_Matrix3x3 child_w_rotation;
+
+ if (parent) {
+
+ // This is a slow parent relation
+ // first compute the normal child world coordinates.
+
+ MT_Vector3 child_n_scale;
+ MT_Point3 child_n_pos;
+ MT_Matrix3x3 child_n_rotation;
+
+ const MT_Vector3 & p_world_scale = parent->GetWorldScaling();
+ const MT_Point3 & p_world_pos = parent->GetWorldPosition();
+ const MT_Matrix3x3 & p_world_rotation = parent->GetWorldOrientation();
+
+ child_n_scale = p_world_scale * child_scale;
+ child_n_rotation = p_world_rotation * child_rotation;
+
+ child_n_pos = p_world_pos + p_world_scale *
+ (p_world_rotation * child_pos);
+
+
+ if (m_initialized) {
+
+ // get the current world positions
+
+ child_w_scale = child->GetWorldScaling();
+ child_w_pos = child->GetWorldPosition();
+ child_w_rotation = child->GetWorldOrientation();
+
+ // now 'interpolate' the normal coordinates with the last
+ // world coordinates to get the new world coordinates.
+
+ // problem 1:
+ // The child world scale needs to be initialized in some way for this
+ // to make sense
+ // problem 2:
+ // This is way of doing interpolation is nonsense
+
+ int i;
+
+ MT_Scalar weight = MT_Scalar(1)/(m_relax + 1);
+ for (i=0;i <3 ;i++) {
+ child_w_scale[i] = (m_relax * child_w_scale[i] + child_n_scale[i]) * weight;
+ child_w_pos[i] = (m_relax * child_w_pos[i] + child_n_pos[i]) * weight;
+ child_w_rotation[0][i] = (m_relax * child_w_rotation[0][i] + child_n_rotation[0][i]) * weight;
+ child_w_rotation[1][i] = (m_relax * child_w_rotation[1][i] + child_n_rotation[1][i]) * weight;
+ child_w_rotation[2][i] = (m_relax * child_w_rotation[2][i] + child_n_rotation[2][i]) * weight;
+ }
+
+ //FIXME: update physics controller.
+ } else {
+ child_w_scale = child_n_scale;
+ child_w_pos = child_n_pos;
+ child_w_rotation = child_n_rotation;
+ m_initialized = true;
+ }
+
+ } else {
+
+ child_w_scale = child_scale;
+ child_w_pos = child_pos;
+ child_w_rotation = child_rotation;
+ }
+
+ child->SetWorldScale(child_w_scale);
+ child->SetWorldPosition(child_w_pos);
+ child->SetWorldOrientation(child_w_rotation);
+
+ return parent != NULL;
+}
+
+/**
+ * Method inherited from KX_ParentRelation
+ */
+
+ SG_ParentRelation *
+KX_SlowParentRelation::
+NewCopy(
+){
+ return new KX_SlowParentRelation(m_relax);
+}
+
+KX_SlowParentRelation::
+KX_SlowParentRelation(
+ MT_Scalar relaxation
+):
+ m_relax(relaxation),
+ m_initialized(false)
+{
+ //nothing to do
+}
+
+KX_SlowParentRelation::
+~KX_SlowParentRelation(
+){
+ //nothing to do
+}
+
+
+
+
diff --git a/source/gameengine/Ketsji/KX_SG_NodeRelationships.h b/source/gameengine/Ketsji/KX_SG_NodeRelationships.h
new file mode 100644
index 00000000000..f434cb5b648
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SG_NodeRelationships.h
@@ -0,0 +1,204 @@
+/**
+ * @mainpage KX_SG_NodeRelationships
+
+ * @section
+ *
+ * This file provides common concrete implementations of
+ * SG_ParentRelation used by the game engine. These are
+ * KX_SlowParentRelation a slow parent relationship.
+ * KX_NormalParentRelation a normal parent relationship where
+ * orientation and position are inherited from the parent by
+ * the child.
+ * KX_VertexParentRelation only location information is
+ * inherited by the child.
+ *
+ * @see SG_ParentRelation for more information about this
+ * 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 __KX_SG_NODERELATIONS_H__
+#define __KX_SG_NODERELATIONS_H__
+
+#include "SG_Spatial.h"
+#include "SG_ParentRelation.h"
+
+class KX_NormalParentRelation : public SG_ParentRelation
+{
+
+public :
+
+ /**
+ * Allocate and construct a new KX_NormalParentRelation
+ * on the heap.
+ */
+
+ static
+ KX_NormalParentRelation *
+ New(
+ );
+
+ /**
+ * Method inherited from KX_ParentRelation
+ */
+
+ bool
+ UpdateChildCoordinates(
+ SG_Spatial * child,
+ const SG_Spatial * parent
+ );
+
+ /**
+ * Method inherited from KX_ParentRelation
+ */
+
+ SG_ParentRelation *
+ NewCopy(
+ );
+
+ ~KX_NormalParentRelation(
+ );
+
+private :
+
+ KX_NormalParentRelation(
+ );
+
+};
+
+
+class KX_VertexParentRelation : public SG_ParentRelation
+{
+
+public :
+
+ /**
+ * Allocate and construct a new KX_VertexParentRelation
+ * on the heap.
+ */
+
+ static
+ KX_VertexParentRelation *
+ New(
+ );
+
+ /**
+ * Method inherited from KX_ParentRelation
+ */
+
+ bool
+ UpdateChildCoordinates(
+ SG_Spatial * child,
+ const SG_Spatial * parent
+ );
+
+ /**
+ * Method inherited from KX_ParentRelation
+ */
+
+ SG_ParentRelation *
+ NewCopy(
+ );
+
+ ~KX_VertexParentRelation(
+ );
+
+private :
+
+ KX_VertexParentRelation(
+ );
+
+};
+
+
+class KX_SlowParentRelation : public SG_ParentRelation
+{
+
+public :
+
+ /**
+ * Allocate and construct a new KX_VertexParentRelation
+ * on the heap.
+ */
+
+ static
+ KX_SlowParentRelation *
+ New(
+ MT_Scalar relaxation
+ );
+
+ /**
+ * Method inherited from KX_ParentRelation
+ */
+
+ bool
+ UpdateChildCoordinates(
+ SG_Spatial * child,
+ const SG_Spatial * parent
+ );
+
+ /**
+ * Method inherited from KX_ParentRelation
+ */
+
+ SG_ParentRelation *
+ NewCopy(
+ );
+
+ ~KX_SlowParentRelation(
+ );
+
+private :
+
+ KX_SlowParentRelation(
+ MT_Scalar relaxation
+ );
+
+ // the relaxation coefficient.
+
+ MT_Scalar m_relax;
+
+ /**
+ * Looks like a hack flag to me.
+ * We need to compute valid world coordinates the first
+ * time we update spatial data of the child. This is done
+ * by just doing a normal parent relation the first time
+ * UpdateChildCoordinates is called and then doing the
+ * slow parent relation
+ */
+
+ bool m_initialized;
+
+};
+
+#endif
diff --git a/source/gameengine/Ketsji/KX_ScalarInterpolator.cpp b/source/gameengine/Ketsji/KX_ScalarInterpolator.cpp
new file mode 100644
index 00000000000..5e036600119
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ScalarInterpolator.cpp
@@ -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 *****
+ */
+
+#include "KX_ScalarInterpolator.h"
+#include "KX_IScalarInterpolator.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void KX_ScalarInterpolator::Execute(float currentTime) const {
+ *m_target = m_ipo->GetValue(currentTime);
+}
diff --git a/source/gameengine/Ketsji/KX_ScalarInterpolator.h b/source/gameengine/Ketsji/KX_ScalarInterpolator.h
new file mode 100644
index 00000000000..72e8203d3c4
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ScalarInterpolator.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef KX_SCALARINTERPOLATOR
+#define KX_SCALARINTERPOLATOR
+
+#include "MT_Scalar.h"
+#include "KX_IInterpolator.h"
+
+class KX_IScalarInterpolator;
+
+class KX_ScalarInterpolator : public KX_IInterpolator {
+public:
+ KX_ScalarInterpolator(MT_Scalar* target,
+ KX_IScalarInterpolator *ipo) :
+ m_target(target),
+ m_ipo(ipo)
+ {}
+
+ virtual ~KX_ScalarInterpolator() {}
+ virtual void Execute(float currentTime) const;
+ void SetNewTarget(MT_Scalar* newtarget)
+ {
+ m_target=newtarget;
+ }
+ MT_Scalar* GetTarget()
+ {
+ return m_target;
+ }
+private:
+ MT_Scalar* m_target;
+ KX_IScalarInterpolator *m_ipo;
+};
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_ScalingInterpolator.cpp b/source/gameengine/Ketsji/KX_ScalingInterpolator.cpp
new file mode 100644
index 00000000000..c645eb6a3ea
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ScalingInterpolator.cpp
@@ -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 *****
+ */
+
+#include "KX_ScalingInterpolator.h"
+#include "MT_Vector3.h"
+#include "KX_IScalarInterpolator.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void KX_ScalingInterpolator::Execute(float currentTime) const {
+ m_target.setValue(m_ipos[0]->GetValue(currentTime),
+ m_ipos[1]->GetValue(currentTime),
+ m_ipos[2]->GetValue(currentTime));
+}
diff --git a/source/gameengine/Ketsji/KX_ScalingInterpolator.h b/source/gameengine/Ketsji/KX_ScalingInterpolator.h
new file mode 100644
index 00000000000..25c5cc87d83
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ScalingInterpolator.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 KX_SCALINGINTERPOLATOR
+#define KX_SCALINGINTERPOLATOR
+
+#include "KX_IInterpolator.h"
+
+class MT_Vector3;
+class KX_IScalarInterpolator;
+
+class KX_ScalingInterpolator : public KX_IInterpolator {
+public:
+ KX_ScalingInterpolator(MT_Vector3& target,
+ KX_IScalarInterpolator *ipos[])
+ : m_target(target)
+ {
+ m_ipos[0] = ipos[0];
+ m_ipos[1] = ipos[1];
+ m_ipos[2] = ipos[2];
+ }
+
+ virtual void Execute(float currentTime) const;
+
+private:
+ MT_Vector3& m_target;
+ KX_IScalarInterpolator *m_ipos[3];
+};
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
new file mode 100644
index 00000000000..996c605df21
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -0,0 +1,1350 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Ketsji scene. Holds references to all scene data.
+ */
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif //WIN32
+
+#include "KX_Scene.h"
+#include "MT_assert.h"
+
+#include "KX_KetsjiEngine.h"
+#include "RAS_IPolygonMaterial.h"
+#include "ListValue.h"
+#include "SCA_LogicManager.h"
+#include "SCA_TimeEventManager.h"
+#include "SCA_AlwaysEventManager.h"
+#include "SCA_RandomEventManager.h"
+#include "KX_RayEventManager.h"
+#include "KX_TouchEventManager.h"
+#include "SCA_KeyboardManager.h"
+#include "SCA_MouseManager.h"
+#include "SCA_PropertyEventManager.h"
+#include "KX_Camera.h"
+#include "SCA_JoystickManager.h"
+
+#include "RAS_MeshObject.h"
+#include "BL_SkinMeshObject.h"
+
+#include "RAS_IRasterizer.h"
+#include "RAS_BucketManager.h"
+
+#include "FloatValue.h"
+#include "SCA_IController.h"
+#include "SCA_IActuator.h"
+#include "SG_Node.h"
+#include "SYS_System.h"
+#include "SG_Controller.h"
+#include "SG_IObject.h"
+#include "SG_Tree.h"
+
+#include "KX_SG_NodeRelationships.h"
+
+#include "KX_NetworkEventManager.h"
+#include "NG_NetworkScene.h"
+#include "PHY_IPhysicsEnvironment.h"
+#include "KX_IPhysicsController.h"
+
+#include "BL_SkinDeformer.h"
+#include "BL_DeformableGameObject.h"
+
+
+void* KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene)
+{
+ KX_GameObject* replica = ((KX_Scene*)scene)->AddNodeReplicaObject(node,(KX_GameObject*)gameobj);
+
+ return (void*)replica;
+}
+
+void* KX_SceneDestructionFunc(SG_IObject* node,void* gameobj,void* scene)
+{
+ ((KX_Scene*)scene)->RemoveNodeDestructObject(node,(KX_GameObject*)gameobj);
+
+ return NULL;
+};
+
+SG_Callbacks KX_Scene::m_callbacks = SG_Callbacks(KX_SceneReplicationFunc,KX_SceneDestructionFunc,KX_GameObject::UpdateTransformFunc);
+
+// temporarily var until there is a button in the userinterface
+// (defined in KX_PythonInit.cpp)
+extern bool gUseVisibilityTemp;
+
+KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
+ class SCA_IInputDevice* mousedevice,
+ class NG_NetworkDeviceInterface *ndi,
+ class SND_IAudioDevice* adi,
+ const STR_String& sceneName):
+ PyObjectPlus(&KX_Scene::Type),
+ m_keyboardmgr(NULL),
+ m_mousemgr(NULL),
+ m_physicsEnvironment(0),
+ m_sceneName(sceneName),
+ m_adi(adi),
+ m_networkDeviceInterface(ndi),
+ m_active_camera(NULL),
+ m_ueberExecutionPriority(0)
+{
+ m_suspendedtime = 0.0;
+ m_suspendeddelta = 0.0;
+
+ m_activity_culling = false;
+ m_suspend = false;
+ m_isclearingZbuffer = true;
+ m_tempObjectList = new CListValue();
+ m_objectlist = new CListValue();
+ m_parentlist = new CListValue();
+ m_lightlist= new CListValue();
+ m_euthanasyobjects = new CListValue();
+ m_delayReleaseObjects = new CListValue();
+
+ m_logicmgr = new SCA_LogicManager();
+
+ m_timemgr = new SCA_TimeEventManager(m_logicmgr);
+ m_keyboardmgr = new SCA_KeyboardManager(m_logicmgr,keyboarddevice);
+ m_mousemgr = new SCA_MouseManager(m_logicmgr,mousedevice);
+
+ SCA_AlwaysEventManager* alwaysmgr = new SCA_AlwaysEventManager(m_logicmgr);
+ SCA_PropertyEventManager* propmgr = new SCA_PropertyEventManager(m_logicmgr);
+ SCA_RandomEventManager* rndmgr = new SCA_RandomEventManager(m_logicmgr);
+ KX_RayEventManager* raymgr = new KX_RayEventManager(m_logicmgr);
+
+ KX_NetworkEventManager* netmgr = new KX_NetworkEventManager(m_logicmgr, ndi);
+
+ SCA_JoystickManager *joymgr = new SCA_JoystickManager(m_logicmgr);
+
+ m_logicmgr->RegisterEventManager(alwaysmgr);
+ m_logicmgr->RegisterEventManager(propmgr);
+ m_logicmgr->RegisterEventManager(m_keyboardmgr);
+ m_logicmgr->RegisterEventManager(m_mousemgr);
+ m_logicmgr->RegisterEventManager(m_timemgr);
+ m_logicmgr->RegisterEventManager(rndmgr);
+ m_logicmgr->RegisterEventManager(raymgr);
+ m_logicmgr->RegisterEventManager(netmgr);
+ m_logicmgr->RegisterEventManager(joymgr);
+
+ m_soundScene = new SND_Scene(adi);
+ MT_assert (m_networkDeviceInterface != NULL);
+ m_networkScene = new NG_NetworkScene(m_networkDeviceInterface);
+
+ m_rootnode = NULL;
+
+ m_bucketmanager=new RAS_BucketManager();
+
+ m_canvasDesignWidth = 0;
+ m_canvasDesignHeight = 0;
+
+ m_attrlist = PyDict_New(); /* new ref */
+}
+
+
+
+KX_Scene::~KX_Scene()
+{
+
+// int numobj = m_objectlist->GetCount();
+
+ //int numrootobjects = GetRootParentList()->GetCount();
+ for (int i = 0; i < GetRootParentList()->GetCount(); i++)
+ {
+ KX_GameObject* parentobj = (KX_GameObject*) GetRootParentList()->GetValue(i);
+ this->RemoveObject(parentobj);
+ }
+
+ if(m_objectlist)
+ m_objectlist->Release();
+
+ if (m_parentlist)
+ m_parentlist->Release();
+
+ if (m_lightlist)
+ m_lightlist->Release();
+
+ if (m_tempObjectList)
+ m_tempObjectList->Release();
+
+ if (m_euthanasyobjects)
+ m_euthanasyobjects->Release();
+ if (m_delayReleaseObjects)
+ m_delayReleaseObjects->Release();
+
+ if (m_logicmgr)
+ delete m_logicmgr;
+
+ if (m_physicsEnvironment)
+ delete m_physicsEnvironment;
+
+ if (m_soundScene)
+ delete m_soundScene;
+
+ if (m_networkScene)
+ delete m_networkScene;
+
+ if (m_bucketmanager)
+ {
+ delete m_bucketmanager;
+ }
+
+ //Py_DECREF(m_attrlist);
+}
+
+
+
+
+void KX_Scene::SetProjectionMatrix(MT_CmMatrix4x4& pmat)
+{
+ m_projectionmat = pmat;
+}
+
+
+
+RAS_BucketManager* KX_Scene::GetBucketManager()
+{
+ return m_bucketmanager;
+}
+
+
+
+CListValue* KX_Scene::GetObjectList()
+{
+ return m_objectlist;
+}
+
+
+
+CListValue* KX_Scene::GetRootParentList()
+{
+ return m_parentlist;
+}
+
+
+
+CListValue* KX_Scene::GetLightList()
+{
+ return m_lightlist;
+}
+
+SCA_LogicManager* KX_Scene::GetLogicManager()
+{
+ return m_logicmgr;
+}
+
+SCA_TimeEventManager* KX_Scene::GetTimeEventManager()
+{
+ return m_timemgr;
+}
+
+
+
+
+set<class KX_Camera*>* KX_Scene::GetCameras()
+{
+ return &m_cameras;
+}
+
+
+
+void KX_Scene::SetFramingType(RAS_FrameSettings & frame_settings)
+{
+ m_frame_settings = frame_settings;
+};
+
+/**
+ * Return a const reference to the framing
+ * type set by the above call.
+ * The contents are not guarenteed to be sensible
+ * if you don't call the above function.
+ */
+const RAS_FrameSettings& KX_Scene::GetFramingType() const
+{
+ return m_frame_settings;
+};
+
+
+
+/**
+ * Store the current scene's viewport on the
+ * game engine canvas.
+ */
+void KX_Scene::SetSceneViewport(const RAS_Rect &viewport)
+{
+ m_viewport = viewport;
+}
+
+
+
+const RAS_Rect& KX_Scene::GetSceneViewport() const
+{
+ return m_viewport;
+}
+
+
+
+void KX_Scene::SetWorldInfo(class KX_WorldInfo* worldinfo)
+{
+ m_worldinfo = worldinfo;
+}
+
+
+
+class KX_WorldInfo* KX_Scene::GetWorldInfo()
+{
+ return m_worldinfo;
+}
+
+
+
+SND_Scene* KX_Scene::GetSoundScene()
+{
+ return m_soundScene;
+}
+
+const STR_String& KX_Scene::GetName()
+{
+ return m_sceneName;
+}
+
+
+void KX_Scene::Suspend()
+{
+ m_suspend = true;
+}
+
+void KX_Scene::Resume()
+{
+ m_suspend = false;
+}
+
+void KX_Scene::SetActivityCulling(bool b)
+{
+ m_activity_culling = b;
+}
+
+bool KX_Scene::IsSuspended()
+{
+ return m_suspend;
+}
+
+bool KX_Scene::IsClearingZBuffer()
+{
+ return m_isclearingZbuffer;
+}
+
+void KX_Scene::EnableZBufferClearing(bool isclearingZbuffer)
+{
+ m_isclearingZbuffer = isclearingZbuffer;
+}
+
+void KX_Scene::RemoveNodeDestructObject(class SG_IObject* node,class CValue* gameobj)
+{
+ KX_GameObject* orgobj = (KX_GameObject*)gameobj;
+ NewRemoveObject(orgobj);
+
+ if (node)
+ delete node;
+}
+
+KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CValue* gameobj)
+{
+ KX_GameObject* orgobj = (KX_GameObject*)gameobj;
+ KX_GameObject* newobj = (KX_GameObject*)orgobj->GetReplica();
+ m_map_gameobject_to_replica.insert(orgobj, newobj);
+
+ // also register 'timers' (time properties) of the replica
+ int numprops = newobj->GetPropertyCount();
+
+ for (int i = 0; i < numprops; i++)
+ {
+ CValue* prop = newobj->GetProperty(i);
+
+ if (prop->GetProperty("timer"))
+ this->m_timemgr->AddTimeProperty(prop);
+ }
+
+ if (node)
+ {
+ newobj->SetSGNode((SG_Node*)node);
+ }
+ else
+ {
+ m_rootnode = new SG_Node(newobj,this,KX_Scene::m_callbacks);
+
+ // this fixes part of the scaling-added object bug
+ SG_Node* orgnode = orgobj->GetSGNode();
+ m_rootnode->SetLocalScale(orgnode->GetLocalScale());
+ m_rootnode->SetLocalPosition(orgnode->GetLocalPosition());
+ m_rootnode->SetLocalOrientation(orgnode->GetLocalOrientation());
+
+ // define the relationship between this node and it's parent.
+ KX_NormalParentRelation * parent_relation =
+ KX_NormalParentRelation::New();
+ m_rootnode->SetParentRelation(parent_relation);
+
+ newobj->SetSGNode(m_rootnode);
+ }
+
+ SG_IObject* replicanode = newobj->GetSGNode();
+// SG_Node* rootnode = (replicanode == m_rootnode ? NULL : m_rootnode);
+
+ replicanode->SetSGClientObject(newobj);
+
+ // this is the list of object that are send to the graphics pipeline
+ m_objectlist->Add(newobj);
+ newobj->Bucketize();
+
+ // logic cannot be replicated, until the whole hierarchy is replicated.
+ m_logicHierarchicalGameObjects.push_back(newobj);
+ //replicate controllers of this node
+ SGControllerList scenegraphcontrollers = orgobj->GetSGNode()->GetSGControllerList();
+ replicanode->RemoveAllControllers();
+ SGControllerList::iterator cit;
+ //int numcont = scenegraphcontrollers.size();
+
+ for (cit = scenegraphcontrollers.begin();!(cit==scenegraphcontrollers.end());++cit)
+ {
+ // controller replication is quite complicated
+ // only replicate ipo and physics controller for now
+
+ SG_Controller* replicacontroller = (*cit)->GetReplica((SG_Node*) replicanode);
+ if (replicacontroller)
+ {
+ replicacontroller->SetObject(replicanode);
+ replicanode->AddSGController(replicacontroller);
+ }
+ }
+
+ return newobj;
+}
+
+
+
+// before calling this method KX_Scene::ReplicateLogic(), make sure to
+// have called 'GameObject::ReParentLogic' for each object this
+// hierarchy that's because first ALL bricks must exist in the new
+// replica of the hierarchy in order to make cross-links work properly
+// !
+void KX_Scene::ReplicateLogic(KX_GameObject* newobj)
+{
+ // also relink the controller to sensors/actuators
+ SCA_ControllerList& controllers = newobj->GetControllers();
+ //SCA_SensorList& sensors = newobj->GetSensors();
+ //SCA_ActuatorList& actuators = newobj->GetActuators();
+
+ for (SCA_ControllerList::iterator itc = controllers.begin(); !(itc==controllers.end());itc++)
+ {
+ SCA_IController* cont = (*itc);
+ cont->SetUeberExecutePriority(m_ueberExecutionPriority);
+ vector<SCA_ISensor*> linkedsensors = cont->GetLinkedSensors();
+ vector<SCA_IActuator*> linkedactuators = cont->GetLinkedActuators();
+
+ // disconnect the sensors and actuators
+ cont->UnlinkAllSensors();
+ cont->UnlinkAllActuators();
+
+ // now relink each sensor
+ for (vector<SCA_ISensor*>::iterator its = linkedsensors.begin();!(its==linkedsensors.end());its++)
+ {
+ SCA_ISensor* oldsensor = (*its);
+ STR_String name = oldsensor->GetName();
+ //find this name in the list
+ SCA_ISensor* newsensor = newobj->FindSensor(name);
+
+ if (newsensor)
+ {
+ // relink this newsensor to the controller
+ m_logicmgr->RegisterToSensor(cont,newsensor);
+ }
+ else
+ {
+ // it can be linked somewhere in the hierarchy or...
+ for (vector<KX_GameObject*>::iterator git = m_logicHierarchicalGameObjects.begin();
+ !(git==m_logicHierarchicalGameObjects.end());++git)
+ {
+ newsensor = (*git)->FindSensor(name);
+ if (newsensor)
+ break;
+ }
+
+ if (newsensor)
+ {
+ // relink this newsensor to the controller somewhere else within this
+ // hierarchy
+ m_logicmgr->RegisterToSensor(cont,newsensor);
+ }
+ else
+ {
+ // must be an external sensor, so...
+ m_logicmgr->RegisterToSensor(cont,oldsensor);
+ }
+ }
+ }
+
+ // now relink each actuator
+ for (vector<SCA_IActuator*>::iterator ita = linkedactuators.begin();!(ita==linkedactuators.end());ita++)
+ {
+ SCA_IActuator* oldactuator = (*ita);
+ STR_String name = oldactuator->GetName();
+ //find this name in the list
+ SCA_IActuator* newactuator = newobj->FindActuator(name);
+ if (newactuator)
+ {
+ // relink this newsensor to the controller
+ m_logicmgr->RegisterToActuator(cont,newactuator);
+ newactuator->SetUeberExecutePriority(m_ueberExecutionPriority);
+ }
+ else
+ {
+ // it can be linked somewhere in the hierarchy or...
+ for (vector<KX_GameObject*>::iterator git = m_logicHierarchicalGameObjects.begin();
+ !(git==m_logicHierarchicalGameObjects.end());++git)
+ {
+ newactuator= (*git)->FindActuator(name);
+ if (newactuator)
+ break;
+ }
+
+ if (newactuator)
+ {
+ // relink this actuator to the controller somewhere else within this
+ // hierarchy
+ m_logicmgr->RegisterToActuator(cont,newactuator);
+ newactuator->SetUeberExecutePriority(m_ueberExecutionPriority);
+ }
+ else
+ {
+ // must be an external actuator, so...
+ m_logicmgr->RegisterToActuator(cont,oldactuator);
+ }
+ }
+ }
+ }
+}
+
+
+
+SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
+ class CValue* parentobject,
+ int lifespan)
+{
+
+ m_logicHierarchicalGameObjects.clear();
+ m_map_gameobject_to_replica.clear();
+
+ // todo: place a timebomb in the object, for temporarily objects :)
+ // lifespan of zero means 'this object lives forever'
+ KX_GameObject* originalobj = (KX_GameObject*) originalobject;
+ KX_GameObject* parentobj = (KX_GameObject*) parentobject;
+
+ m_ueberExecutionPriority++;
+
+ // lets create a replica
+ KX_GameObject* replica = (KX_GameObject*) AddNodeReplicaObject(NULL,originalobj);
+
+ if (lifespan > 0)
+ {
+ // add a timebomb to this object
+ // for now, convert between so called frames and realtime
+ m_tempObjectList->Add(replica->AddRef());
+ replica->SetProperty("::timebomb",new CFloatValue(lifespan*0.02));
+ }
+
+ // add to 'rootparent' list (this is the list of top hierarchy objects, updated each frame)
+ m_parentlist->Add(replica->AddRef());
+
+ // recurse replication into children nodes
+
+ NodeList& children = originalobj->GetSGNode()->GetSGChildren();
+
+ replica->GetSGNode()->ClearSGChildren();
+ for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit)
+ {
+ SG_Node* orgnode = (*childit);
+ SG_Node* childreplicanode = orgnode->GetSGReplica();
+ replica->GetSGNode()->AddChild(childreplicanode);
+ }
+
+ // relink any pointers as necessary, sort of a temporary solution
+ vector<KX_GameObject*>::iterator git;
+ for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
+ {
+ (*git)->Relink(&m_map_gameobject_to_replica);
+ }
+
+ // now replicate logic
+ for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
+ {
+ (*git)->ReParentLogic();
+ }
+
+ // replicate crosslinks etc. between logic bricks
+ for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
+ {
+ ReplicateLogic((*git));
+ }
+
+ MT_Point3 newpos = ((KX_GameObject*) parentobject)->NodeGetWorldPosition();
+ replica->NodeSetLocalPosition(newpos);
+
+ MT_Matrix3x3 newori = ((KX_GameObject*) parentobject)->NodeGetWorldOrientation();
+ replica->NodeSetLocalOrientation(newori);
+
+ // get the rootnode's scale
+ MT_Vector3 newscale = parentobj->GetSGNode()->GetRootSGParent()->GetLocalScale();
+
+ // set the replica's relative scale with the rootnode's scale
+ replica->NodeSetRelativeScale(newscale);
+
+ if (replica->GetPhysicsController())
+ {
+ replica->GetPhysicsController()->setPosition(newpos);
+ replica->GetPhysicsController()->setOrientation(newori.getRotation());
+ replica->GetPhysicsController()->setScaling(newscale);
+ }
+
+ // here we want to set the relative scale: the rootnode's scale will override all other
+ // scalings, so lets better prepare for it
+
+
+ replica->GetSGNode()->UpdateWorldData(0);
+ replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox());
+ replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius());
+
+ return replica;
+}
+
+
+
+void KX_Scene::RemoveObject(class CValue* gameobj)
+{
+ KX_GameObject* newobj = (KX_GameObject*) gameobj;
+
+ // first disconnect child from parent
+ SG_Node* node = newobj->GetSGNode();
+
+ if (node)
+ {
+ node->DisconnectFromParent();
+
+ // recursively destruct
+ node->Destruct();
+ }
+ newobj->SetSGNode(0);
+}
+
+void KX_Scene::DelayedReleaseObject(CValue* gameobj)
+{
+ m_delayReleaseObjects->Add(gameobj->AddRef());
+}
+
+
+void KX_Scene::DelayedRemoveObject(class CValue* gameobj)
+{
+ //KX_GameObject* newobj = (KX_GameObject*) gameobj;
+ if (!m_euthanasyobjects->SearchValue(gameobj))
+ {
+ m_euthanasyobjects->Add(gameobj->AddRef());
+ }
+}
+
+
+
+void KX_Scene::NewRemoveObject(class CValue* gameobj)
+{
+ KX_GameObject* newobj = (KX_GameObject*) gameobj;
+
+ //todo: look at this
+ //GetPhysicsEnvironment()->RemovePhysicsController(gameobj->getPhysicsController());
+
+ // remove all sensors/controllers/actuators from logicsystem...
+
+ SCA_SensorList& sensors = newobj->GetSensors();
+ for (SCA_SensorList::iterator its = sensors.begin();
+ !(its==sensors.end());its++)
+ {
+ m_logicmgr->RemoveSensor(*its);
+ }
+
+ SCA_ControllerList& controllers = newobj->GetControllers();
+ for (SCA_ControllerList::iterator itc = controllers.begin();
+ !(itc==controllers.end());itc++)
+ {
+ (*itc)->UnlinkAllSensors();
+ (*itc)->UnlinkAllActuators();
+ }
+
+ SCA_ActuatorList& actuators = newobj->GetActuators();
+ for (SCA_ActuatorList::iterator ita = actuators.begin();
+ !(ita==actuators.end());ita++)
+ {
+ m_logicmgr->RemoveDestroyedActuator(*ita);
+ }
+
+ // now remove the timer properties from the time manager
+ int numprops = newobj->GetPropertyCount();
+
+ for (int i = 0; i < numprops; i++)
+ {
+ CValue* propval = newobj->GetProperty(i);
+ if (propval->GetProperty("timer"))
+ {
+ m_timemgr->RemoveTimeProperty(propval);
+ }
+ }
+
+ newobj->RemoveMeshes();
+ if (m_objectlist->RemoveValue(newobj))
+ newobj->Release();
+ if (m_tempObjectList->RemoveValue(newobj))
+ newobj->Release();
+ if (m_parentlist->RemoveValue(newobj))
+ newobj->Release();
+ if (m_euthanasyobjects->RemoveValue(newobj))
+ newobj->Release();
+
+ if (newobj == m_active_camera)
+ {
+ m_active_camera->Release();
+ m_active_camera = NULL;
+ }
+}
+
+
+
+void KX_Scene::ReplaceMesh(class CValue* gameobj,void* meshobj)
+{
+ KX_GameObject* newobj = static_cast<KX_GameObject*>(gameobj);
+ RAS_MeshObject* mesh = static_cast<RAS_MeshObject*>(meshobj);
+
+ const STR_String origMeshName = newobj->GetMesh(0)->GetName();
+
+ if( !newobj || !mesh )
+ {
+ std::cout << "warning: invalid object, mesh will not be replaced" << std::endl;
+ return;
+ }
+
+ newobj->RemoveMeshes();
+ newobj->AddMesh(mesh);
+
+ bool isDeformer = (newobj->m_isDeformable && mesh->m_class == 1);
+ if(isDeformer)
+ {
+ /* FindBlendObjByGameObj() can return 0...
+ In the case of 0 here,
+ the replicated object that is calling this function
+ is some how not in the map. (which is strange because it's added)
+ So we will search the map by the first mesh name
+ to try to locate it there. If its still not found
+ spit some message rather than crash
+ */
+ Object* blendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameObj(newobj));
+ Object* oldblendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(mesh->GetName()));
+
+ bool parSkin = blendobj && blendobj->parent && blendobj->parent->type == OB_ARMATURE && blendobj->partype==PARSKEL;
+ bool releaseParent = true;
+ KX_GameObject* parentobj = newobj->GetParent();
+
+
+ // lookup by mesh name if blendobj is 0
+ if( !blendobj && parentobj )
+ {
+ blendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(origMeshName));
+
+ // replace the mesh on the parent armature
+ if( blendobj )
+ parSkin = parentobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE;
+
+ // can't do it
+ else
+ std::cout << "warning: child object for " << parentobj->GetName().ReadPtr()
+ << " not found, and can't create!" << std::endl;
+ }
+
+ if( blendobj && oldblendobj )
+ {
+ isDeformer = (static_cast<Mesh*>(blendobj->data)->dvert != 0);
+ BL_DeformableGameObject* deformIter =0;
+
+ // armature parent
+ if( parSkin && isDeformer )
+ {
+ deformIter = static_cast<BL_DeformableGameObject*>( newobj );
+ delete deformIter->m_pDeformer;
+
+ BL_SkinDeformer* skinDeformer = new BL_SkinDeformer(
+ oldblendobj, blendobj,
+ static_cast<BL_SkinMeshObject*>(mesh),
+ true,
+ static_cast<BL_ArmatureObject*>( parentobj )
+ );
+ releaseParent= false;
+ deformIter->m_pDeformer = skinDeformer;
+ }
+
+ // normal deformer
+ if( !parSkin && isDeformer)
+ {
+ deformIter = static_cast<BL_DeformableGameObject*>( newobj );
+ delete deformIter->m_pDeformer;
+
+ BL_MeshDeformer* meshdeformer = new BL_MeshDeformer(
+ oldblendobj, static_cast<BL_SkinMeshObject*>(mesh)
+ );
+
+ deformIter->m_pDeformer = meshdeformer;
+ }
+ }
+ // release parent reference if its not being used
+ if( releaseParent && parentobj)
+ parentobj->Release();
+ }
+ newobj->Bucketize();
+}
+
+
+
+MT_CmMatrix4x4& KX_Scene::GetViewMatrix()
+{
+ MT_Scalar cammat[16];
+ m_active_camera->GetWorldToCamera().getValue(cammat);
+ m_viewmat = cammat;
+ return m_viewmat;
+}
+
+
+
+MT_CmMatrix4x4& KX_Scene::GetProjectionMatrix()
+{
+ return m_projectionmat;
+}
+
+
+KX_Camera* KX_Scene::FindCamera(KX_Camera* cam)
+{
+ set<KX_Camera*>::iterator it = m_cameras.begin();
+
+ while ( (it != m_cameras.end())
+ && ((*it) != cam) ) {
+ it++;
+ }
+
+ return ((it == m_cameras.end()) ? NULL : (*it));
+}
+
+
+KX_Camera* KX_Scene::FindCamera(STR_String& name)
+{
+ set<KX_Camera*>::iterator it = m_cameras.begin();
+
+ while ( (it != m_cameras.end())
+ && ((*it)->GetName() != name) ) {
+ it++;
+ }
+
+ return ((it == m_cameras.end()) ? NULL : (*it));
+}
+
+void KX_Scene::AddCamera(KX_Camera* cam)
+{
+ m_cameras.insert(cam);
+}
+
+KX_Camera* KX_Scene::GetActiveCamera()
+{
+ // NULL if not defined
+ return m_active_camera;
+}
+
+
+void KX_Scene::SetActiveCamera(KX_Camera* cam)
+{
+ // only set if the cam is in the active list? Or add it otherwise?
+ if (!FindCamera(cam)){
+ AddCamera(cam);
+ if (cam) std::cout << "Added cam " << cam->GetName() << std::endl;
+ }
+
+ m_active_camera = cam;
+}
+
+
+
+void KX_Scene::UpdateMeshTransformations()
+{
+ // do this incrementally in the future
+ for (int i = 0; i < m_objectlist->GetCount(); i++)
+ {
+ KX_GameObject* gameobj = (KX_GameObject*)m_objectlist->GetValue(i);
+ gameobj->GetOpenGLMatrix();
+// gameobj->UpdateNonDynas();
+ }
+}
+
+void KX_Scene::MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera* cam)
+{
+ int intersect = KX_Camera::INTERSECT;
+ KX_GameObject *gameobj = node->Client()?(KX_GameObject*) node->Client()->GetSGClientObject():NULL;
+ bool dotest = (gameobj && gameobj->GetVisible()) || node->Left() || node->Right();
+
+ /* If the camera is inside the box, assume intersect. */
+ if (dotest && !node->inside( cam->NodeGetWorldPosition()))
+ {
+ MT_Scalar radius = node->Radius();
+ MT_Point3 center = node->Center();
+
+ intersect = cam->SphereInsideFrustum(center, radius);
+
+ if (intersect == KX_Camera::INTERSECT)
+ {
+ MT_Point3 box[8];
+ node->get(box);
+ intersect = cam->BoxInsideFrustum(box);
+ }
+ }
+
+ switch (intersect)
+ {
+ case KX_Camera::OUTSIDE:
+ MarkSubTreeVisible(node, rasty, false, cam);
+ break;
+ case KX_Camera::INTERSECT:
+ if (gameobj)
+ MarkVisible(rasty, gameobj,cam);
+ if (node->Left())
+ MarkVisible(node->Left(), rasty,cam);
+ if (node->Right())
+ MarkVisible(node->Right(), rasty,cam);
+ break;
+ case KX_Camera::INSIDE:
+ MarkSubTreeVisible(node, rasty, true,cam);
+ break;
+ }
+}
+
+void KX_Scene::MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible,KX_Camera* cam)
+{
+ if (node->Client())
+ {
+ KX_GameObject *gameobj = (KX_GameObject*) node->Client()->GetSGClientObject();
+ if (gameobj->GetVisible())
+ {
+ if (visible)
+ {
+ int nummeshes = gameobj->GetMeshCount();
+ MT_Transform t( cam->GetWorldToCamera() * gameobj->GetSGNode()->GetWorldTransform());
+
+
+ for (int m=0;m<nummeshes;m++)
+ {
+ // this adds the vertices to the display list
+ (gameobj->GetMesh(m))->SchedulePolygons(t, rasty->GetDrawingMode());
+ }
+ }
+ gameobj->MarkVisible(visible);
+ }
+ }
+ if (node->Left())
+ MarkSubTreeVisible(node->Left(), rasty, visible,cam);
+ if (node->Right())
+ MarkSubTreeVisible(node->Right(), rasty, visible,cam);
+}
+
+void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Camera* cam)
+{
+ // User (Python/Actuator) has forced object invisible...
+ if (!gameobj->GetVisible())
+ return;
+ // If Frustum culling is off, the object is always visible.
+ bool vis = !cam->GetFrustumCulling();
+
+ // If the camera is inside this node, then the object is visible.
+ if (!vis)
+ {
+ vis = gameobj->GetSGNode()->inside( GetActiveCamera()->GetCameraLocation() );
+ }
+
+ // Test the object's bound sphere against the view frustum.
+ if (!vis)
+ {
+ MT_Vector3 scale = gameobj->GetSGNode()->GetWorldScaling();
+ MT_Scalar radius = fabs(scale[scale.closestAxis()] * gameobj->GetSGNode()->Radius());
+ switch (cam->SphereInsideFrustum(gameobj->NodeGetWorldPosition(), radius))
+ {
+ case KX_Camera::INSIDE:
+ vis = true;
+ break;
+ case KX_Camera::OUTSIDE:
+ vis = false;
+ break;
+ case KX_Camera::INTERSECT:
+ // Test the object's bound box against the view frustum.
+ MT_Point3 box[8];
+ gameobj->GetSGNode()->getBBox(box);
+ vis = cam->BoxInsideFrustum(box) != KX_Camera::OUTSIDE;
+ break;
+ }
+ }
+
+ if (vis)
+ {
+ int nummeshes = gameobj->GetMeshCount();
+ MT_Transform t(cam->GetWorldToCamera() * gameobj->GetSGNode()->GetWorldTransform());
+
+ for (int m=0;m<nummeshes;m++)
+ {
+ // this adds the vertices to the display list
+ (gameobj->GetMesh(m))->SchedulePolygons(t, rasty->GetDrawingMode());
+ }
+ // Visibility/ non-visibility are marked
+ // elsewhere now.
+ gameobj->MarkVisible();
+ } else {
+ gameobj->MarkVisible(false);
+ }
+}
+
+void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam)
+{
+// FIXME: When tree is operational
+#if 1
+ // do this incrementally in the future
+ for (int i = 0; i < m_objectlist->GetCount(); i++)
+ {
+ MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam);
+ }
+#else
+ if (cam->GetFrustumCulling())
+ MarkVisible(m_objecttree, rasty, cam);
+ else
+ MarkSubTreeVisible(m_objecttree, rasty, true, cam);
+#endif
+}
+
+// logic stuff
+void KX_Scene::LogicBeginFrame(double curtime)
+{
+ // have a look at temp objects ...
+ int lastobj = m_tempObjectList->GetCount() - 1;
+
+ for (int i = lastobj; i >= 0; i--)
+ {
+ CValue* objval = m_tempObjectList->GetValue(i);
+ CFloatValue* propval = (CFloatValue*) objval->GetProperty("::timebomb");
+
+ if (propval)
+ {
+ float timeleft = propval->GetNumber() - 1.0/KX_KetsjiEngine::GetTicRate();
+
+ if (timeleft > 0)
+ {
+ propval->SetFloat(timeleft);
+ }
+ else
+ {
+ DelayedRemoveObject(objval);
+ // remove obj
+ }
+ }
+ else
+ {
+ // all object is the tempObjectList should have a clock
+ }
+ }
+ m_logicmgr->BeginFrame(curtime, 1.0/KX_KetsjiEngine::GetTicRate());
+}
+
+
+
+void KX_Scene::LogicUpdateFrame(double curtime, bool frame)
+{
+ m_logicmgr->UpdateFrame(curtime, frame);
+}
+
+
+
+void KX_Scene::LogicEndFrame()
+{
+ m_logicmgr->EndFrame();
+ int numobj = m_euthanasyobjects->GetCount();
+ int i;
+ for (i = numobj - 1; i >= 0; i--)
+ {
+ KX_GameObject* gameobj = (KX_GameObject*)m_euthanasyobjects->GetValue(i);
+ this->RemoveObject(gameobj);
+ }
+
+ numobj= m_delayReleaseObjects->GetCount();
+ for (i = numobj-1;i>=0;i--)
+ {
+ KX_GameObject* gameobj = (KX_GameObject*)m_delayReleaseObjects->GetValue(i);
+ m_delayReleaseObjects->RemoveValue(gameobj);
+
+ }
+
+
+}
+
+
+
+/**
+ * UpdateParents: SceneGraph transformation update.
+ */
+void KX_Scene::UpdateParents(double curtime)
+{
+// int numrootobjects = GetRootParentList()->GetCount();
+
+ for (int i=0; i<GetRootParentList()->GetCount(); i++)
+ {
+ KX_GameObject* parentobj = (KX_GameObject*)GetRootParentList()->GetValue(i);
+ parentobj->NodeUpdateGS(curtime,true);
+ }
+}
+
+
+
+RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat)
+{
+ return m_bucketmanager->RAS_BucketManagerFindBucket(polymat);
+}
+
+
+
+void KX_Scene::RenderBuckets(const MT_Transform & cameratransform,
+ class RAS_IRasterizer* rasty,
+ class RAS_IRenderTools* rendertools)
+{
+ m_bucketmanager->Renderbuckets(cameratransform,rasty,rendertools);
+}
+
+
+
+void KX_Scene::UpdateObjectActivity(void)
+{
+ if (m_activity_culling) {
+ /* determine the activity criterium and set objects accordingly */
+ int i=0;
+
+ MT_Point3 camloc = GetActiveCamera()->NodeGetWorldPosition(); //GetCameraLocation();
+
+ for (i=0;i<GetObjectList()->GetCount();i++)
+ {
+ KX_GameObject* ob = (KX_GameObject*) GetObjectList()->GetValue(i);
+
+ if (!ob->GetIgnoreActivityCulling()) {
+ /* Simple test: more than 10 away from the camera, count
+ * Manhattan distance. */
+ MT_Point3 obpos = ob->NodeGetWorldPosition();
+
+ if ( (fabs(camloc[0] - obpos[0]) > m_activity_box_radius)
+ || (fabs(camloc[1] - obpos[1]) > m_activity_box_radius)
+ || (fabs(camloc[2] - obpos[2]) > m_activity_box_radius) )
+ {
+ ob->Suspend();
+ } else {
+ ob->Resume();
+ }
+ }
+ }
+ }
+}
+
+void KX_Scene::SetActivityCullingRadius(float f)
+{
+ if (f < 0.5)
+ f = 0.5;
+ m_activity_box_radius = f;
+}
+
+NG_NetworkDeviceInterface* KX_Scene::GetNetworkDeviceInterface()
+{
+ return m_networkDeviceInterface;
+}
+
+NG_NetworkScene* KX_Scene::GetNetworkScene()
+{
+ return m_networkScene;
+}
+
+void KX_Scene::SetNetworkDeviceInterface(NG_NetworkDeviceInterface* newInterface)
+{
+ m_networkDeviceInterface = newInterface;
+}
+
+void KX_Scene::SetNetworkScene(NG_NetworkScene *newScene)
+{
+ m_networkScene = newScene;
+}
+
+
+void KX_Scene::SetGravity(const MT_Vector3& gravity)
+{
+ GetPhysicsEnvironment()->setGravity(gravity[0],gravity[1],gravity[2]);
+}
+
+void KX_Scene::SetNodeTree(SG_Tree* root)
+{
+ m_objecttree = root;
+}
+
+void KX_Scene::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* physEnv)
+{
+ m_physicsEnvironment = physEnv;
+
+ KX_TouchEventManager* touchmgr = new KX_TouchEventManager(m_logicmgr, physEnv);
+ m_logicmgr->RegisterEventManager(touchmgr);
+ return;
+}
+
+void KX_Scene::setSuspendedTime(double suspendedtime)
+{
+ m_suspendedtime = suspendedtime;
+}
+double KX_Scene::getSuspendedTime()
+{
+ return m_suspendedtime;
+}
+void KX_Scene::setSuspendedDelta(double suspendeddelta)
+{
+ m_suspendeddelta = suspendeddelta;
+}
+double KX_Scene::getSuspendedDelta()
+{
+ return m_suspendeddelta;
+}
+
+//----------------------------------------------------------------------------
+//Python
+
+PyMethodDef KX_Scene::Methods[] = {
+ KX_PYMETHODTABLE(KX_Scene, getLightList),
+ KX_PYMETHODTABLE(KX_Scene, getObjectList),
+ KX_PYMETHODTABLE(KX_Scene, getName),
+
+ {NULL,NULL} //Sentinel
+};
+
+PyTypeObject KX_Scene::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_Scene",
+ sizeof(KX_Scene),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0, 0
+};
+
+PyParentObject KX_Scene::Parents[] = {
+ &KX_Scene::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyObject* KX_Scene::_getattr(const STR_String& attr)
+{
+ if (attr == "name")
+ return PyString_FromString(GetName());
+
+ if (attr == "active_camera")
+ {
+ KX_Camera *camera = GetActiveCamera();
+ camera->AddRef();
+ return (PyObject*) camera;
+ }
+
+ if (attr == "suspended")
+ return PyInt_FromLong(m_suspend);
+
+ if (attr == "activity_culling")
+ return PyInt_FromLong(m_activity_culling);
+
+ if (attr == "activity_culling_radius")
+ return PyFloat_FromDouble(m_activity_box_radius);
+
+ PyObject* value = PyDict_GetItemString(m_attrlist, const_cast<char *>(attr.ReadPtr()));
+ if (value)
+ {
+ Py_INCREF(value);
+ return value;
+ }
+
+ _getattr_up(PyObjectPlus);
+}
+
+int KX_Scene::_delattr(const STR_String &attr)
+{
+ PyDict_DelItemString(m_attrlist, const_cast<char *>(attr.ReadPtr()));
+ return 0;
+}
+
+int KX_Scene::_setattr(const STR_String &attr, PyObject *pyvalue)
+{
+
+ if (!PyDict_SetItemString(m_attrlist, const_cast<char *>(attr.ReadPtr()), pyvalue))
+ return 0;
+
+ return PyObjectPlus::_setattr(attr, pyvalue);
+}
+
+KX_PYMETHODDEF_DOC(KX_Scene, getLightList,
+"getLightList() -> list [KX_Light]\n"
+"Returns a list of all lights in the scene.\n"
+)
+{
+ m_lightlist->AddRef();
+ return (PyObject*) m_lightlist;
+}
+
+KX_PYMETHODDEF_DOC(KX_Scene, getObjectList,
+"getObjectList() -> list [KX_GameObject]\n"
+"Returns a list of all game objects in the scene.\n"
+)
+{
+ m_objectlist->AddRef();
+ return (PyObject*) m_objectlist;
+}
+
+KX_PYMETHODDEF_DOC(KX_Scene, getName,
+"getName() -> string\n"
+"Returns the name of the scene.\n"
+)
+{
+ return PyString_FromString(GetName());
+}
diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h
new file mode 100644
index 00000000000..ba479c5e543
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_Scene.h
@@ -0,0 +1,557 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_SCENE_H
+#define __KX_SCENE_H
+
+
+#include "KX_PhysicsEngineEnums.h"
+
+#include "MT_CmMatrix4x4.h"
+
+#include <vector>
+#include <set>
+
+#include "GEN_Map.h"
+#include "GEN_HashedPtr.h"
+#include "SG_IObject.h"
+#include "SCA_IScene.h"
+#include "MT_Transform.h"
+#include "SND_Scene.h"
+#include "RAS_FramingManager.h"
+#include "RAS_Rect.h"
+
+#include "PyObjectPlus.h"
+
+/**
+ * @section Forward declarations
+ */
+struct SM_MaterialProps;
+struct SM_ShapeProps;
+
+class GEN_HashedPtr;
+class CListValue;
+class CValue;
+class SCA_LogicManager;
+class SCA_KeyboardManager;
+class SCA_TimeEventManager;
+class SCA_MouseManager;
+class SCA_ISystem;
+class SCA_IInputDevice;
+class SND_Scene;
+class SND_IAudioDevice;
+class NG_NetworkDeviceInterface;
+class NG_NetworkScene;
+class SG_IObject;
+class SG_Node;
+class SG_Tree;
+class KX_WorldInfo;
+class KX_Camera;
+class KX_GameObject;
+class KX_LightObject;
+class RAS_BucketManager;
+class RAS_BucketManager;
+class RAS_MaterialBucket;
+class RAS_IPolyMaterial;
+class RAS_IRasterizer;
+class RAS_IRenderTools;
+class SCA_JoystickManager;
+/**
+ * The KX_Scene holds all data for an independent scene. It relates
+ * KX_Objects to the specific objects in the modules.
+ * */
+class KX_Scene : public PyObjectPlus, public SCA_IScene
+{
+ Py_Header;
+protected:
+ RAS_BucketManager* m_bucketmanager;
+ CListValue* m_tempObjectList;
+
+ /**
+ * The list of objects which have been removed during the
+ * course of one frame. They are actually destroyed in
+ * LogicEndFrame() via a call to RemoveObject().
+ */
+ CListValue* m_euthanasyobjects;
+ /**
+ * The list of objects that couldn't be released during logic update.
+ * for example, AddObject actuator sometimes releases an object that was cached from previous frame
+ */
+ CListValue* m_delayReleaseObjects;
+
+ CListValue* m_objectlist;
+ CListValue* m_parentlist; // all 'root' parents
+ CListValue* m_lightlist;
+
+ /**
+ * The tree of objects in the scene.
+ */
+ SG_Tree* m_objecttree;
+
+ /**
+ * The set of cameras for this scene
+ */
+ set<class KX_Camera*> m_cameras;
+
+ /**
+ * Various SCA managers used by the scene
+ */
+ SCA_LogicManager* m_logicmgr;
+ SCA_KeyboardManager* m_keyboardmgr;
+ SCA_MouseManager* m_mousemgr;
+ SCA_TimeEventManager* m_timemgr;
+
+ /**
+ * physics engine abstraction
+ */
+
+ //e_PhysicsEngine m_physicsEngine; //who needs this ?
+ class PHY_IPhysicsEnvironment* m_physicsEnvironment;
+
+ /**
+ * Does this scene clear the z-buffer?
+ */
+ bool m_isclearingZbuffer;
+
+ /**
+ * The name of the scene
+ */
+ STR_String m_sceneName;
+
+ /**
+ * stores the worldsettings for a scene
+ */
+ KX_WorldInfo* m_worldinfo;
+
+ /**
+ * @section Different scenes, linked to ketsji scene
+ */
+
+
+ /**
+ * Sound scenes
+ */
+ SND_Scene* m_soundScene;
+ SND_IAudioDevice* m_adi;
+
+ /**
+ * Network scene.
+ */
+ NG_NetworkDeviceInterface* m_networkDeviceInterface;
+ NG_NetworkScene* m_networkScene;
+
+ /**
+ * A temoprary variable used to parent objects together on
+ * replication. Don't get confused by the name it is not
+ * the scene's root node!
+ */
+ SG_Node* m_rootnode;
+
+ /**
+ * The active camera for the scene
+ */
+ KX_Camera* m_active_camera;
+
+ /**
+ * The projection and view matrices of this scene
+ * The projection matrix is computed externally by KX_Engine
+ * The view mat is stored as a side effect of GetViewMatrix()
+ * and is totally unnessary.
+ */
+ MT_CmMatrix4x4 m_projectionmat;
+ MT_CmMatrix4x4 m_viewmat;
+
+ /** Desired canvas width set at design time. */
+ unsigned int m_canvasDesignWidth;
+ /** Desired canvas height set at design time. */
+ unsigned int m_canvasDesignHeight;
+
+ /**
+ * Another temporary variable outstaying its welcome
+ * used in AddReplicaObject to map game objects to their
+ * replicas so pointers can be updated.
+ */
+ GEN_Map <GEN_HashedPtr, void*> m_map_gameobject_to_replica;
+
+ /**
+ * Another temporary variable outstaying its welcome
+ * used in AddReplicaObject to keep a record of all added
+ * objects. Logic can only be updated when all objects
+ * have been updated. This stores a list of the new objects.
+ */
+ std::vector<KX_GameObject*> m_logicHierarchicalGameObjects;
+
+ /**
+ * Pointer to system variable passed in in constructor
+ * only used in constructor so we do not need to keep it
+ * around in this class.
+ */
+
+ SCA_ISystem* m_kxsystem;
+
+ /**
+ * The execution priority of replicated object actuators?
+ */
+ int m_ueberExecutionPriority;
+
+ /**
+ * Activity 'bubble' settings :
+ * Suspend (freeze) the entire scene.
+ */
+ bool m_suspend;
+
+ /**
+ * Radius in Manhattan distance of the box for activity culling.
+ */
+ float m_activity_box_radius;
+
+ /**
+ * Toggle to enable or disable activity culling.
+ */
+ bool m_activity_culling;
+
+ /**
+ * The framing settings used by this scene
+ */
+
+ RAS_FrameSettings m_frame_settings;
+
+ /**
+ * This scenes viewport into the game engine
+ * canvas.Maintained externally, initially [0,0] -> [0,0]
+ */
+ RAS_Rect m_viewport;
+
+ /**
+ * Visibility testing functions.
+ */
+ void MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera*cam);
+ void MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible, KX_Camera*cam);
+ void MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj, KX_Camera*cam);
+
+ double m_suspendedtime;
+ double m_suspendeddelta;
+
+ /**
+ * This stores anything from python
+ */
+ PyObject* m_attrlist;
+
+public:
+ KX_Scene(class SCA_IInputDevice* keyboarddevice,
+ class SCA_IInputDevice* mousedevice,
+ class NG_NetworkDeviceInterface* ndi,
+ class SND_IAudioDevice* adi,
+ const STR_String& scenename );
+
+ virtual
+ ~KX_Scene();
+
+ RAS_BucketManager* GetBucketManager();
+ RAS_MaterialBucket* FindBucket(RAS_IPolyMaterial* polymat);
+ void RenderBuckets(const MT_Transform& cameratransform,
+ RAS_IRasterizer* rasty,
+ RAS_IRenderTools* rendertools);
+ /**
+ * Update all transforms according to the scenegraph.
+ */
+ void UpdateParents(double curtime);
+ SCA_IObject* AddReplicaObject(CValue* gameobj,
+ CValue* locationobj,
+ int lifespan=0);
+ KX_GameObject* AddNodeReplicaObject(SG_IObject* node,
+ CValue* gameobj);
+ void RemoveNodeDestructObject(SG_IObject* node,
+ CValue* gameobj);
+ void RemoveObject(CValue* gameobj);
+ void DelayedRemoveObject(CValue* gameobj);
+
+ void DelayedReleaseObject(CValue* gameobj);
+
+ void NewRemoveObject(CValue* gameobj);
+ void ReplaceMesh(CValue* gameobj,
+ void* meshobj);
+ /**
+ * @section Logic stuff
+ * Initiate an update of the logic system.
+ */
+ void LogicBeginFrame(double curtime);
+ void LogicUpdateFrame(double curtime, bool frame);
+
+ void
+ LogicEndFrame(
+ );
+
+ CListValue*
+ GetObjectList(
+ );
+
+ CListValue*
+ GetRootParentList(
+ );
+
+ CListValue*
+ GetLightList(
+ );
+
+ SCA_LogicManager*
+ GetLogicManager(
+ );
+
+ SCA_TimeEventManager*
+ GetTimeEventManager(
+ );
+
+ set<class KX_Camera*>*
+ GetCameras(
+ );
+
+
+ /** Find a camera in the scene by pointer. */
+ KX_Camera*
+ FindCamera(
+ KX_Camera*
+ );
+
+ /** Find a scene in the scene by name. */
+ KX_Camera*
+ FindCamera(
+ STR_String&
+ );
+
+ /** Add a camera to this scene. */
+ void
+ AddCamera(
+ KX_Camera*
+ );
+
+ /** Find the currently active camera. */
+ KX_Camera*
+ GetActiveCamera(
+ );
+
+ /**
+ * Set this camera to be the active camera in the scene. If the
+ * camera is not present in the camera list, it will be added
+ */
+
+ void
+ SetActiveCamera(
+ class KX_Camera*
+ );
+
+ /** Return the viewmatrix as used by the last frame. */
+ MT_CmMatrix4x4&
+ GetViewMatrix(
+ );
+
+ /**
+ * Return the projectionmatrix as used by the last frame. This is
+ * set by hand :)
+ */
+ MT_CmMatrix4x4&
+ GetProjectionMatrix(
+ );
+
+ /** Sets the projection matrix. */
+ void
+ SetProjectionMatrix(
+ MT_CmMatrix4x4& pmat
+ );
+
+ /**
+ * Activates new desired canvas width set at design time.
+ * @param width The new desired width.
+ */
+ void
+ SetCanvasDesignWidth(
+ unsigned int width
+ );
+ /**
+ * Activates new desired canvas height set at design time.
+ * @param width The new desired height.
+ */
+ void
+ SetCanvasDesignHeight(
+ unsigned int height
+ );
+ /**
+ * Returns the current desired canvas width set at design time.
+ * @return The desired width.
+ */
+ unsigned int
+ GetCanvasDesignWidth(
+ void
+ ) const;
+
+ /**
+ * Returns the current desired canvas height set at design time.
+ * @return The desired height.
+ */
+ unsigned int
+ GetCanvasDesignHeight(
+ void
+ ) const;
+
+ /**
+ * Set the framing options for this scene
+ */
+
+ void
+ SetFramingType(
+ RAS_FrameSettings & frame_settings
+ );
+
+ /**
+ * Return a const reference to the framing
+ * type set by the above call.
+ * The contents are not guarenteed to be sensible
+ * if you don't call the above function.
+ */
+
+ const
+ RAS_FrameSettings &
+ GetFramingType(
+ ) const;
+
+ /**
+ * Store the current scene's viewport on the
+ * game engine canvas.
+ */
+ void SetSceneViewport(const RAS_Rect &viewport);
+
+ /**
+ * Get the current scene's viewport on the
+ * game engine canvas. This maintained
+ * externally in KX_GameEngine
+ */
+ const RAS_Rect& GetSceneViewport() const;
+
+ /**
+ * @section Accessors to different scenes of this scene
+ */
+ void SetNetworkDeviceInterface(NG_NetworkDeviceInterface* newInterface);
+ void SetNetworkScene(NG_NetworkScene *newScene);
+ void SetWorldInfo(class KX_WorldInfo* wi);
+ KX_WorldInfo* GetWorldInfo();
+ void CalculateVisibleMeshes(RAS_IRasterizer* rasty, KX_Camera *cam);
+ void UpdateMeshTransformations();
+ KX_Camera* GetpCamera();
+ SND_Scene* GetSoundScene();
+ NG_NetworkDeviceInterface* GetNetworkDeviceInterface();
+ NG_NetworkScene* GetNetworkScene();
+
+ /**
+ * Replicate the logic bricks associated to this object.
+ */
+
+ void ReplicateLogic(class KX_GameObject* newobj);
+ static SG_Callbacks m_callbacks;
+
+ const STR_String& GetName();
+
+ // Suspend the entire scene.
+ void Suspend();
+
+ // Resume a suspended scene.
+ void Resume();
+
+ // Update the activity box settings for objects in this scene, if needed.
+ void UpdateObjectActivity(void);
+
+ // Enable/disable activity culling.
+ void SetActivityCulling(bool b);
+
+ // Set the radius of the activity culling box.
+ void SetActivityCullingRadius(float f);
+ bool IsSuspended();
+ bool IsClearingZBuffer();
+ void EnableZBufferClearing(bool isclearingZbuffer);
+
+ class PHY_IPhysicsEnvironment* GetPhysicsEnvironment()
+ {
+ return m_physicsEnvironment;
+ }
+
+ void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* physEnv);
+
+ void SetGravity(const MT_Vector3& gravity);
+
+ /**
+ * Sets the node tree for this scene.
+ */
+ void SetNodeTree(SG_Tree* root);
+
+ KX_PYMETHOD_DOC(KX_Scene, getLightList);
+ KX_PYMETHOD_DOC(KX_Scene, getObjectList);
+ KX_PYMETHOD_DOC(KX_Scene, getName);
+/*
+ KX_PYMETHOD_DOC(KX_Scene, getActiveCamera);
+ KX_PYMETHOD_DOC(KX_Scene, getActiveCamera);
+ KX_PYMETHOD_DOC(KX_Scene, findCamera);
+
+ KX_PYMETHOD_DOC(KX_Scene, getGravity);
+
+ KX_PYMETHOD_DOC(KX_Scene, setActivityCulling);
+ KX_PYMETHOD_DOC(KX_Scene, setActivityCullingRadius);
+
+ KX_PYMETHOD_DOC(KX_Scene, setSceneViewport);
+ KX_PYMETHOD_DOC(KX_Scene, setSceneViewport);
+ */
+
+ virtual PyObject* _getattr(const STR_String& attr); /* name, active_camera, gravity, suspended, viewport, framing, activity_culling, activity_culling_radius */
+ virtual int _setattr(const STR_String &attr, PyObject *pyvalue);
+ virtual int _delattr(const STR_String &attr);
+
+ /**
+ * Sets the time the scene was suspended
+ */
+ void setSuspendedTime(double suspendedtime);
+ /**
+ * Returns the "curtime" the scene was suspended
+ */
+ double getSuspendedTime();
+ /**
+ * Sets the difference between the local time of the scene (when it
+ * was running and not suspended) and the "curtime"
+ */
+ void setSuspendedDelta(double suspendeddelta);
+ /**
+ * Returns the difference between the local time of the scene (when it
+ * was running and not suspended) and the "curtime"
+ */
+ double getSuspendedDelta();
+};
+
+typedef std::vector<KX_Scene*> KX_SceneList;
+
+#endif //__KX_SCENE_H
+
diff --git a/source/gameengine/Ketsji/KX_SceneActuator.cpp b/source/gameengine/Ketsji/KX_SceneActuator.cpp
new file mode 100644
index 00000000000..a37fce434be
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SceneActuator.cpp
@@ -0,0 +1,359 @@
+/**
+* Set scene/camera 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 *****
+*/
+
+#include "SCA_IActuator.h"
+#include "KX_SceneActuator.h"
+#include <iostream>
+#include "KX_Scene.h"
+#include "KX_Camera.h"
+#include "KX_KetsjiEngine.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+KX_SceneActuator::KX_SceneActuator(SCA_IObject *gameobj,
+ int mode,
+ KX_Scene *scene,
+ KX_KetsjiEngine* ketsjiEngine,
+ const STR_String& nextSceneName,
+ KX_Camera* camera,
+ PyTypeObject* T)
+ : SCA_IActuator(gameobj, T)
+{
+ m_mode = mode;
+ m_scene = scene;
+ m_KetsjiEngine=ketsjiEngine;
+ m_camera = camera;
+ m_nextSceneName = nextSceneName;
+} /* End of constructor */
+
+
+
+KX_SceneActuator::~KX_SceneActuator()
+{
+ // there's nothing to be done here, really....
+} /* end of destructor */
+
+
+
+CValue* KX_SceneActuator::GetReplica()
+{
+ KX_SceneActuator* replica = new KX_SceneActuator(*this);
+ replica->ProcessReplica();
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+
+
+bool KX_SceneActuator::Update()
+{
+ // bool result = false; /*unused*/
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (bNegativeEvent)
+ return false; // do nothing on negative events
+
+ switch (m_mode)
+ {
+ case KX_SCENE_RESTART:
+ {
+ m_KetsjiEngine->ReplaceScene(m_scene->GetName(),m_scene->GetName());
+ break;
+ }
+ case KX_SCENE_SET_CAMERA:
+ if (m_camera)
+ {
+ m_scene->SetActiveCamera(m_camera);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!m_nextSceneName.Length())
+ return false;
+
+ switch (m_mode)
+ {
+ case KX_SCENE_SET_SCENE:
+ {
+ m_KetsjiEngine->ReplaceScene(m_scene->GetName(),m_nextSceneName);
+ break;
+ }
+ case KX_SCENE_ADD_FRONT_SCENE:
+ {
+ bool overlay=true;
+ m_KetsjiEngine->ConvertAndAddScene(m_nextSceneName,overlay);
+ break;
+ }
+ case KX_SCENE_ADD_BACK_SCENE:
+ {
+ bool overlay=false;
+ m_KetsjiEngine->ConvertAndAddScene(m_nextSceneName,overlay);
+ break;
+ }
+ case KX_SCENE_REMOVE_SCENE:
+ {
+ m_KetsjiEngine->RemoveScene(m_nextSceneName);
+ break;
+ }
+ case KX_SCENE_SUSPEND:
+ {
+ m_KetsjiEngine->SuspendScene(m_nextSceneName);
+ break;
+ }
+ case KX_SCENE_RESUME:
+ {
+ m_KetsjiEngine->ResumeScene(m_nextSceneName);
+ break;
+ }
+ default:
+ ; /* do nothing? this is an internal error !!! */
+ }
+
+ return false;
+}
+
+
+
+/* returns a camera if the name is valid */
+KX_Camera* KX_SceneActuator::FindCamera(char *camName)
+{
+ KX_SceneList* sl = m_KetsjiEngine->CurrentScenes();
+ STR_String name = STR_String(camName);
+ KX_SceneList::iterator it = sl->begin();
+ KX_Camera* cam = NULL;
+
+ while ((it != sl->end()) && (!cam))
+ {
+ cam = (*it)->FindCamera(name);
+ it++;
+ }
+
+ return cam;
+}
+
+
+
+KX_Scene* KX_SceneActuator::FindScene(char * sceneName)
+{
+ return m_KetsjiEngine->FindScene(sceneName);
+}
+
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_SceneActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_SceneActuator",
+ sizeof(KX_SceneActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+
+PyParentObject KX_SceneActuator::Parents[] =
+{
+ &KX_SceneActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+PyMethodDef KX_SceneActuator::Methods[] =
+{
+ {"setUseRestart", (PyCFunction) KX_SceneActuator::sPySetUseRestart, METH_VARARGS, SetUseRestart_doc},
+ {"setScene", (PyCFunction) KX_SceneActuator::sPySetScene, METH_VARARGS, SetScene_doc},
+ {"setCamera", (PyCFunction) KX_SceneActuator::sPySetCamera, METH_VARARGS, SetCamera_doc},
+ {"getUseRestart", (PyCFunction) KX_SceneActuator::sPyGetUseRestart, METH_VARARGS, GetUseRestart_doc},
+ {"getScene", (PyCFunction) KX_SceneActuator::sPyGetScene, METH_VARARGS, GetScene_doc},
+ {"getCamera", (PyCFunction) KX_SceneActuator::sPyGetCamera, METH_VARARGS, GetCamera_doc},
+ {NULL,NULL} //Sentinel
+};
+
+
+
+PyObject* KX_SceneActuator::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_IActuator);
+}
+
+
+
+/* 2. setUseRestart--------------------------------------------------------- */
+char KX_SceneActuator::SetUseRestart_doc[] =
+"setUseRestart(flag)\n"
+"\t- flag: 0 or 1.\n"
+"\tSet flag to 1 to restart the scene.\n" ;
+PyObject* KX_SceneActuator::PySetUseRestart(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int boolArg;
+
+ if (!PyArg_ParseTuple(args, "i", &boolArg))
+ {
+ return NULL;
+ }
+
+ m_restart = boolArg != 0;
+
+ Py_Return;
+}
+
+
+
+/* 3. getUseRestart: */
+char KX_SceneActuator::GetUseRestart_doc[] =
+"getUseRestart()\n"
+"\tReturn whether the scene will be restarted.\n" ;
+PyObject* KX_SceneActuator::PyGetUseRestart(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyInt_FromLong(!(m_restart == 0));
+}
+
+
+
+/* 4. set scene------------------------------------------------------------- */
+char KX_SceneActuator::SetScene_doc[] =
+"setScene(scene)\n"
+"\t- scene: string\n"
+"\tSet the name of scene the actuator will switch to.\n" ;
+PyObject* KX_SceneActuator::PySetScene(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ /* one argument: a scene, ignore the rest */
+ char *scene_name;
+
+ if(!PyArg_ParseTuple(args, "s", &scene_name))
+ {
+ return NULL;
+ }
+
+ /* Scene switch is done by name. */
+ m_nextSceneName = scene_name;
+
+ Py_Return;
+}
+
+
+
+/* 5. getScene: */
+char KX_SceneActuator::GetScene_doc[] =
+"getScene()\n"
+"\tReturn the name of the scene the actuator wants to switch to.\n" ;
+PyObject* KX_SceneActuator::PyGetScene(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyString_FromString(m_nextSceneName);
+}
+
+
+
+/* 6. set camera------------------------------------------------------------ */
+char KX_SceneActuator::SetCamera_doc[] =
+"setCamera(camera)\n"
+"\t- camera: string\n"
+"\tSet the camera to switch to.\n" ;
+PyObject* KX_SceneActuator::PySetCamera(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject *cam;
+ if (PyArg_ParseTuple(args, "O!", &KX_Camera::Type, &cam))
+ {
+ m_camera = (KX_Camera*) cam;
+ Py_Return;
+ }
+ PyErr_Clear();
+
+ /* one argument: a scene, ignore the rest */
+ char *camName;
+ if(!PyArg_ParseTuple(args, "s", &camName))
+ {
+ return NULL;
+ }
+
+ KX_Camera *camOb = FindCamera(camName);
+ if (camOb) m_camera = camOb;
+
+ Py_Return;
+}
+
+
+
+/* 7. getCamera: */
+char KX_SceneActuator::GetCamera_doc[] =
+"getCamera()\n"
+"\tReturn the name of the camera to switch to.\n" ;
+PyObject* KX_SceneActuator::PyGetCamera(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyString_FromString(m_camera->GetName());
+}
+/* eof */
diff --git a/source/gameengine/Ketsji/KX_SceneActuator.h b/source/gameengine/Ketsji/KX_SceneActuator.h
new file mode 100644
index 00000000000..6416e0f48d0
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SceneActuator.h
@@ -0,0 +1,116 @@
+
+//
+// Add object to the game world on action of this actuator
+//
+// $Id$
+//
+// ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version. The Blender
+// Foundation also sells licenses for use in proprietary software under
+// the Blender License. See http://www.blender.org/BL/ for information
+// about this.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// The Original Code is Copyright (C) 2001-2002 by 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 __KX_SCENEACTUATOR
+#define __KX_SCENEACTUATOR
+
+#include "SCA_IActuator.h"
+
+class KX_SceneActuator : public SCA_IActuator
+{
+ Py_Header;
+
+ int m_mode;
+ // (restart) has become a toggle internally... not in the interface though
+ bool m_restart;
+ // (set Scene) Scene
+ /** The current scene. */
+ class KX_Scene* m_scene;
+ class KX_KetsjiEngine* m_KetsjiEngine;
+ /** The scene to switch to. */
+ STR_String m_nextSceneName;
+
+ // (Set Camera) Object
+ class KX_Camera* m_camera;
+
+ /** Is this a valid scene? */
+ class KX_Scene* FindScene(char* sceneName);
+ /** Is this a valid camera? */
+ class KX_Camera* FindCamera(char* cameraName);
+
+ public:
+ enum SCA_SceneActuatorMode
+ {
+ KX_SCENE_NODEF = 0,
+ KX_SCENE_RESTART,
+ KX_SCENE_SET_SCENE,
+ KX_SCENE_SET_CAMERA,
+ KX_SCENE_ADD_FRONT_SCENE,
+ KX_SCENE_ADD_BACK_SCENE,
+ KX_SCENE_REMOVE_SCENE,
+ KX_SCENE_SUSPEND,
+ KX_SCENE_RESUME,
+ KX_SCENE_MAX
+ };
+
+ KX_SceneActuator(SCA_IObject* gameobj,
+ int mode,
+ KX_Scene* scene,
+ KX_KetsjiEngine* ketsjiEngine,
+ const STR_String& nextSceneName,
+ KX_Camera* camera,
+ PyTypeObject* T=&Type);
+ virtual ~KX_SceneActuator();
+
+ virtual CValue* GetReplica();
+
+ virtual bool Update();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ /* 1. set */
+ /* Removed */
+
+ /* 2. setUseRestart: */
+ KX_PYMETHOD_DOC(KX_SceneActuator,SetUseRestart);
+ /* 3. getUseRestart: */
+ KX_PYMETHOD_DOC(KX_SceneActuator,GetUseRestart);
+ /* 4. setScene: */
+ KX_PYMETHOD_DOC(KX_SceneActuator,SetScene);
+ /* 5. getScene: */
+ KX_PYMETHOD_DOC(KX_SceneActuator,GetScene);
+ /* 6. setCamera: */
+ KX_PYMETHOD_DOC(KX_SceneActuator,SetCamera);
+ /* 7. getCamera: */
+ KX_PYMETHOD_DOC(KX_SceneActuator,GetCamera);
+
+}; /* end of class KXSceneActuator */
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp
new file mode 100644
index 00000000000..f7a2001fcdf
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp
@@ -0,0 +1,497 @@
+/**
+ * KX_SoundActuator.cpp
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_SoundActuator.h"
+#include "SND_SoundObject.h"
+#include "KX_GameObject.h"
+#include "SND_SoundObject.h"
+#include "SND_Scene.h" // needed for replication
+#include <iostream>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj,
+ SND_SoundObject* sndobj,
+ SND_Scene* sndscene,
+ KX_SOUNDACT_TYPE type,
+ short start,
+ short end,
+ PyTypeObject* T)
+ : SCA_IActuator(gameobj,T)
+{
+ m_soundObject = sndobj;
+ m_soundScene = sndscene;
+ m_type = type;
+ m_lastEvent = true;
+ m_isplaying = false;
+ m_startFrame = start;
+ m_endFrame = end;
+ m_pino = false;
+
+
+}
+
+
+
+KX_SoundActuator::~KX_SoundActuator()
+{
+ //m_soundScene->RemoveObject(this->m_soundObject);
+ //(this->m_soundObject)->DeleteWhenFinished();
+ m_soundScene->RemoveActiveObject(m_soundObject);
+// m_soundScene->DeleteObjectWhenFinished(m_soundObject);
+ m_soundScene->DeleteObject(m_soundObject);
+}
+
+
+
+CValue* KX_SoundActuator::GetReplica()
+{
+ KX_SoundActuator* replica = new KX_SoundActuator(*this);
+ replica->ProcessReplica();
+ SND_SoundObject* soundobj = new SND_SoundObject(*m_soundObject);
+ replica->setSoundObject(soundobj);
+ m_soundScene->AddObject(soundobj);
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+};
+
+
+
+bool KX_SoundActuator::Update(double curtime, bool frame)
+{
+ if (!frame)
+ return true;
+ bool result = false;
+
+ // do nothing on negative events, otherwise sounds are played twice!
+ bool bNegativeEvent = IsNegativeEvent();
+
+ RemoveAllEvents();
+
+ if (m_pino)
+ {
+ bNegativeEvent = true;
+ m_pino = false;
+ }
+
+ if (bNegativeEvent)
+ {
+ // here must be a check if it is still playing
+ m_isplaying = false;
+
+ switch (m_type)
+ {
+ case KX_SOUNDACT_PLAYSTOP:
+ case KX_SOUNDACT_LOOPSTOP:
+ case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP:
+ {
+ m_soundScene->RemoveActiveObject(m_soundObject);
+ break;
+ }
+ case KX_SOUNDACT_PLAYEND:
+ {
+ m_soundObject->SetPlaystate(SND_MUST_STOP_WHEN_FINISHED);
+ break;
+ }
+ default:
+ // implement me !!
+ break;
+ }
+ }
+ else
+ {
+ if (m_soundObject && !m_isplaying)
+ {
+ switch (m_type)
+ {
+ case KX_SOUNDACT_LOOPBIDIRECTIONAL:
+ case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP:
+ {
+ m_soundObject->SetLoopMode(SND_LOOP_BIDIRECTIONAL);
+ m_soundScene->AddActiveObject(m_soundObject, curtime);
+ m_isplaying = true;
+ result = true;
+ break;
+ }
+ case KX_SOUNDACT_LOOPEND:
+ case KX_SOUNDACT_LOOPSTOP:
+ {
+ m_soundObject->SetLoopMode(SND_LOOP_NORMAL);
+ m_soundScene->AddActiveObject(m_soundObject, curtime);
+ m_isplaying = true;
+ result = true;
+ break;
+ }
+ case KX_SOUNDACT_PLAYSTOP:
+ case KX_SOUNDACT_PLAYEND:
+ {
+ m_soundObject->SetLoopMode(SND_LOOP_OFF);
+ m_soundScene->AddActiveObject(m_soundObject, curtime);
+ m_isplaying = true;
+ result = true;
+ break;
+ }
+ default:
+ // implement me !!
+ break;
+ }
+ }
+ }
+
+ if (m_isplaying)
+ {
+ m_soundObject->SetPosition(((KX_GameObject*)this->GetParent())->NodeGetWorldPosition());
+ m_soundObject->SetVelocity(((KX_GameObject*)this->GetParent())->GetLinearVelocity());
+ m_soundObject->SetOrientation(((KX_GameObject*)this->GetParent())->NodeGetWorldOrientation());
+ result = true;
+ }
+ else
+ {
+ result = false;
+ }
+
+ if (result && (m_soundObject->IsLifeSpanOver(curtime)) && ((m_type == KX_SOUNDACT_PLAYEND) || (m_type == KX_SOUNDACT_PLAYSTOP)))
+ {
+ m_pino = true;
+ }
+
+ return result;
+}
+
+
+
+void KX_SoundActuator::setSoundObject(class SND_SoundObject* soundobject)
+{
+ m_soundObject = soundobject;
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_SoundActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_SoundActuator",
+ sizeof(KX_SoundActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+
+PyParentObject KX_SoundActuator::Parents[] = {
+ &KX_SoundActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+PyMethodDef KX_SoundActuator::Methods[] = {
+ {"setFilename", (PyCFunction) KX_SoundActuator::sPySetFilename, METH_VARARGS,NULL},
+ {"getFilename", (PyCFunction) KX_SoundActuator::sPyGetFilename, METH_VARARGS,NULL},
+ {"startSound",(PyCFunction) KX_SoundActuator::sPyStartSound,METH_VARARGS,NULL},
+ {"pauseSound",(PyCFunction) KX_SoundActuator::sPyPauseSound,METH_VARARGS,NULL},
+ {"stopSound",(PyCFunction) KX_SoundActuator::sPyStopSound,METH_VARARGS,NULL},
+ {"setGain",(PyCFunction) KX_SoundActuator::sPySetGain,METH_VARARGS,NULL},
+ {"getGain",(PyCFunction) KX_SoundActuator::sPyGetGain,METH_VARARGS,NULL},
+ {"setPitch",(PyCFunction) KX_SoundActuator::sPySetPitch,METH_VARARGS,NULL},
+ {"getPitch",(PyCFunction) KX_SoundActuator::sPyGetPitch,METH_VARARGS,NULL},
+ {"setRollOffFactor",(PyCFunction) KX_SoundActuator::sPySetRollOffFactor,METH_VARARGS,NULL},
+ {"getRollOffFactor",(PyCFunction) KX_SoundActuator::sPyGetRollOffFactor,METH_VARARGS,NULL},
+ {"setLooping",(PyCFunction) KX_SoundActuator::sPySetLooping,METH_VARARGS,NULL},
+ {"getLooping",(PyCFunction) KX_SoundActuator::sPyGetLooping,METH_VARARGS,NULL},
+ {"setPosition",(PyCFunction) KX_SoundActuator::sPySetPosition,METH_VARARGS,NULL},
+ {"setVelocity",(PyCFunction) KX_SoundActuator::sPySetVelocity,METH_VARARGS,NULL},
+ {"setOrientation",(PyCFunction) KX_SoundActuator::sPySetOrientation,METH_VARARGS,NULL},
+ {"setType",(PyCFunction) KX_SoundActuator::sPySetType,METH_VARARGS,NULL},
+ {"getType",(PyCFunction) KX_SoundActuator::sPyGetType,METH_VARARGS,NULL},
+ {NULL,NULL,NULL,NULL} //Sentinel
+};
+
+
+
+PyObject* KX_SoundActuator::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_IActuator);
+}
+
+
+
+PyObject* KX_SoundActuator::PySetFilename(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ char *soundName = NULL;
+ // void *soundPointer = NULL; /*unused*/
+
+ if (!PyArg_ParseTuple(args, "s", &soundName))
+ return NULL;
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_SoundActuator::PyGetFilename(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ STR_String objectname = m_soundObject->GetObjectName();
+ char* name = objectname.Ptr();
+
+ if (!name) {
+ Py_Return; /* internal error */
+ } else
+ return PyString_FromString(name);
+}
+
+
+
+PyObject* KX_SoundActuator::PyStartSound(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ m_soundObject->StartSound();
+ Py_Return;
+}
+
+
+
+PyObject* KX_SoundActuator::PyPauseSound(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ m_soundObject->PauseSound();
+ Py_Return;
+}
+
+
+
+PyObject* KX_SoundActuator::PyStopSound(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ m_soundObject->StopSound();
+ Py_Return;
+}
+
+
+
+PyObject* KX_SoundActuator::PySetGain(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ float gain = 1.0;
+ if (!PyArg_ParseTuple(args, "f", &gain))
+ return NULL;
+
+ m_soundObject->SetGain(gain);
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_SoundActuator::PyGetGain(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ float gain = m_soundObject->GetGain();
+ PyObject* result = PyFloat_FromDouble(gain);
+
+ return result;
+}
+
+
+
+PyObject* KX_SoundActuator::PySetPitch(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ float pitch = 1.0;
+ if (!PyArg_ParseTuple(args, "f", &pitch))
+ return NULL;
+
+ m_soundObject->SetPitch(pitch);
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_SoundActuator::PyGetPitch(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ float pitch = m_soundObject->GetPitch();
+ PyObject* result = PyFloat_FromDouble(pitch);
+
+ return result;
+}
+
+
+
+PyObject* KX_SoundActuator::PySetRollOffFactor(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ float rollofffactor = 1.0;
+ if (!PyArg_ParseTuple(args, "f", &rollofffactor))
+ return NULL;
+
+ m_soundObject->SetRollOffFactor(rollofffactor);
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_SoundActuator::PyGetRollOffFactor(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ float rollofffactor = m_soundObject->GetRollOffFactor();
+ PyObject* result = PyFloat_FromDouble(rollofffactor);
+
+ return result;
+}
+
+
+
+PyObject* KX_SoundActuator::PySetLooping(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ bool looping = 1;
+ if (!PyArg_ParseTuple(args, "i", &looping))
+ return NULL;
+
+ m_soundObject->SetLoopMode(looping);
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_SoundActuator::PyGetLooping(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int looping = m_soundObject->GetLoopMode();
+ PyObject* result = PyInt_FromLong(looping);
+
+ return result;
+}
+
+
+
+PyObject* KX_SoundActuator::PySetPosition(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ MT_Point3 pos;
+ pos[0] = 0.0;
+ pos[1] = 0.0;
+ pos[2] = 0.0;
+
+ if (!PyArg_ParseTuple(args, "fff", &pos[0], &pos[1], &pos[2]))
+ return NULL;
+
+ m_soundObject->SetPosition(pos);
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_SoundActuator::PySetVelocity(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ MT_Vector3 vel;
+ vel[0] = 0.0;
+ vel[1] = 0.0;
+ vel[2] = 0.0;
+
+ if (!PyArg_ParseTuple(args, "fff", &vel[0], &vel[1], &vel[2]))
+ return NULL;
+
+ m_soundObject->SetVelocity(vel);
+
+ Py_Return;
+}
+
+
+
+PyObject* KX_SoundActuator::PySetOrientation(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ MT_Matrix3x3 ori;
+ ori[0][0] = 1.0;
+ ori[0][1] = 0.0;
+ ori[0][2] = 0.0;
+ ori[1][0] = 0.0;
+ ori[1][1] = 1.0;
+ ori[1][2] = 0.0;
+ ori[2][0] = 0.0;
+ ori[2][1] = 0.0;
+ ori[2][2] = 1.0;
+
+ if (!PyArg_ParseTuple(args, "fffffffff", &ori[0][0], &ori[0][1], &ori[0][2], &ori[1][0], &ori[1][1], &ori[1][2], &ori[2][0], &ori[2][1], &ori[2][2]))
+ return NULL;
+
+ m_soundObject->SetOrientation(ori);
+
+ Py_Return;
+}
+
+PyObject* KX_SoundActuator::PySetType(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int typeArg;
+
+ if (!PyArg_ParseTuple(args, "i", &typeArg)) {
+ return NULL;
+ }
+
+ if ( (typeArg > KX_SOUNDACT_NODEF)
+ && (typeArg < KX_SOUNDACT_MAX) ) {
+ m_type = (KX_SOUNDACT_TYPE) typeArg;
+ }
+
+ Py_Return;
+}
+
+PyObject* KX_SoundActuator::PyGetType(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyInt_FromLong(m_type);
+}
+
+
+
diff --git a/source/gameengine/Ketsji/KX_SoundActuator.h b/source/gameengine/Ketsji/KX_SoundActuator.h
new file mode 100644
index 00000000000..796e202df70
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SoundActuator.h
@@ -0,0 +1,109 @@
+/**
+ * KX_SoundActuator.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 __KX_SOUNDACTUATOR
+#define __KX_SOUNDACTUATOR
+
+#include "SCA_IActuator.h"
+
+class KX_SoundActuator : public SCA_IActuator
+{
+ Py_Header;
+ bool m_lastEvent;
+ bool m_isplaying;
+ /* just some handles to the audio-data... */
+ class SND_SoundObject* m_soundObject;
+ class SND_Scene* m_soundScene;
+ short m_startFrame;
+ short m_endFrame;
+ bool m_pino;
+public:
+
+ enum KX_SOUNDACT_TYPE
+ {
+ KX_SOUNDACT_NODEF = 0,
+ KX_SOUNDACT_PLAYSTOP,
+ KX_SOUNDACT_PLAYEND,
+ KX_SOUNDACT_LOOPSTOP,
+ KX_SOUNDACT_LOOPEND,
+ KX_SOUNDACT_LOOPBIDIRECTIONAL,
+ KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP,
+ KX_SOUNDACT_MAX
+ };
+
+ KX_SOUNDACT_TYPE m_type;
+
+ KX_SoundActuator(SCA_IObject* gameobj,
+ class SND_SoundObject* sndobj,
+ class SND_Scene* sndscene,
+ KX_SOUNDACT_TYPE type,
+ short start,
+ short end,
+ PyTypeObject* T=&Type);
+
+ ~KX_SoundActuator();
+
+ void setSoundObject(class SND_SoundObject* soundobject);
+ virtual bool Update(double curtime, bool frame);
+
+ CValue* GetReplica();
+
+ /* -------------------------------------------------------------------- */
+ /* Python interface --------------------------------------------------- */
+ /* -------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ KX_PYMETHOD(KX_SoundActuator,SetFilename);
+ KX_PYMETHOD(KX_SoundActuator,GetFilename);
+ KX_PYMETHOD(KX_SoundActuator,StartSound);
+ KX_PYMETHOD(KX_SoundActuator,PauseSound);
+ KX_PYMETHOD(KX_SoundActuator,StopSound);
+ KX_PYMETHOD(KX_SoundActuator,SetGain);
+ KX_PYMETHOD(KX_SoundActuator,GetGain);
+ KX_PYMETHOD(KX_SoundActuator,SetPitch);
+ KX_PYMETHOD(KX_SoundActuator,GetPitch);
+ KX_PYMETHOD(KX_SoundActuator,SetRollOffFactor);
+ KX_PYMETHOD(KX_SoundActuator,GetRollOffFactor);
+ KX_PYMETHOD(KX_SoundActuator,SetLooping);
+ KX_PYMETHOD(KX_SoundActuator,GetLooping);
+ KX_PYMETHOD(KX_SoundActuator,SetPosition);
+ KX_PYMETHOD(KX_SoundActuator,SetVelocity);
+ KX_PYMETHOD(KX_SoundActuator,SetOrientation);
+ KX_PYMETHOD(KX_SoundActuator,SetType);
+ KX_PYMETHOD(KX_SoundActuator,GetType);
+};
+
+#endif //__KX_SOUNDACTUATOR
+
diff --git a/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp b/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp
new file mode 100644
index 00000000000..6ea5461dbaa
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp
@@ -0,0 +1,229 @@
+#include "KX_ConvertPhysicsObject.h"
+
+#ifdef USE_SUMO_SOLID
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif
+
+#include "KX_SumoPhysicsController.h"
+#include "SG_Spatial.h"
+#include "SM_Scene.h"
+#include "KX_GameObject.h"
+#include "KX_MotionState.h"
+#include "KX_ClientObjectInfo.h"
+
+#include "PHY_IPhysicsEnvironment.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void KX_SumoPhysicsController::applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse)
+{
+ SumoPhysicsController::applyImpulse(attach[0],attach[1],attach[2],impulse[0],impulse[1],impulse[2]);
+}
+void KX_SumoPhysicsController::RelativeTranslate(const MT_Vector3& dloc,bool local)
+{
+ SumoPhysicsController::RelativeTranslate(dloc[0],dloc[1],dloc[2],local);
+
+}
+void KX_SumoPhysicsController::RelativeRotate(const MT_Matrix3x3& drot,bool local)
+{
+ float oldmat[12];
+ drot.getValue(oldmat);
+/* float newmat[9];
+ float *m = &newmat[0];
+ double *orgm = &oldmat[0];
+
+ *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++;
+ *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++;
+ *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++; */
+
+ SumoPhysicsController::RelativeRotate(oldmat,local);
+}
+
+void KX_SumoPhysicsController::SetLinearVelocity(const MT_Vector3& lin_vel,bool local)
+{
+ SumoPhysicsController::SetLinearVelocity(lin_vel[0],lin_vel[1],lin_vel[2],local);
+
+}
+
+void KX_SumoPhysicsController::SetAngularVelocity(const MT_Vector3& ang_vel,bool local)
+{
+ SumoPhysicsController::SetAngularVelocity(ang_vel[0],ang_vel[1],ang_vel[2],local);
+}
+
+MT_Vector3 KX_SumoPhysicsController::GetVelocity(const MT_Point3& pos)
+{
+
+ float linvel[3];
+ SumoPhysicsController::GetVelocity(pos[0],pos[1],pos[2],linvel[0],linvel[1],linvel[2]);
+
+ return MT_Vector3 (linvel);
+}
+
+MT_Vector3 KX_SumoPhysicsController::GetLinearVelocity()
+{
+ return GetVelocity(MT_Point3(0,0,0));
+
+}
+
+void KX_SumoPhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ)
+{
+ SumoPhysicsController::resolveCombinedVelocities(linvelX,linvelY,linvelZ,angVelX,angVelY,angVelZ);
+}
+
+void KX_SumoPhysicsController::ApplyTorque(const MT_Vector3& torque,bool local)
+{
+ SumoPhysicsController::ApplyTorque(torque[0],torque[1],torque[2],local);
+
+}
+
+void KX_SumoPhysicsController::ApplyForce(const MT_Vector3& force,bool local)
+{
+ SumoPhysicsController::ApplyForce(force[0],force[1],force[2],local);
+}
+
+bool KX_SumoPhysicsController::Update(double time)
+{
+ return SynchronizeMotionStates(time);
+}
+
+void KX_SumoPhysicsController::SetSimulatedTime(double time)
+{
+
+}
+
+void KX_SumoPhysicsController::SetSumoTransform(bool nondynaonly)
+{
+ SumoPhysicsController::setSumoTransform(nondynaonly);
+
+}
+
+void KX_SumoPhysicsController::SuspendDynamics()
+{
+ SumoPhysicsController::SuspendDynamics();
+}
+
+void KX_SumoPhysicsController::RestoreDynamics()
+{
+ SumoPhysicsController::RestoreDynamics();
+}
+
+SG_Controller* KX_SumoPhysicsController::GetReplica(SG_Node* destnode)
+{
+
+ PHY_IMotionState* motionstate = new KX_MotionState(destnode);
+
+ KX_SumoPhysicsController* physicsreplica = new KX_SumoPhysicsController(*this);
+
+ //parentcontroller is here be able to avoid collisions between parent/child
+
+ PHY_IPhysicsController* parentctrl = NULL;
+
+ if (destnode != destnode->GetRootSGParent())
+ {
+ KX_GameObject* clientgameobj = (KX_GameObject*) destnode->GetRootSGParent()->GetSGClientObject();
+ if (clientgameobj)
+ {
+ parentctrl = (KX_SumoPhysicsController*)clientgameobj->GetPhysicsController();
+ } else
+ {
+ // it could be a false node, try the children
+ NodeList::const_iterator childit;
+ for (
+ childit = destnode->GetSGChildren().begin();
+ childit!= destnode->GetSGChildren().end();
+ ++childit
+ ) {
+ KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject());
+ if (clientgameobj)
+ {
+ parentctrl = (KX_SumoPhysicsController*)clientgameobj->GetPhysicsController();
+ }
+ }
+ }
+ }
+
+ physicsreplica->PostProcessReplica(motionstate,parentctrl);
+
+ return physicsreplica;
+}
+
+
+void KX_SumoPhysicsController::SetObject (SG_IObject* object)
+{
+ SG_Controller::SetObject(object);
+
+ // cheating here...
+//should not be necessary, is it for duplicates ?
+
+KX_GameObject* gameobj = (KX_GameObject*) object->GetSGClientObject();
+gameobj->SetPhysicsController(this,gameobj->IsDynamic());
+GetSumoObject()->setClientObject(gameobj->getClientInfo());
+}
+
+void KX_SumoPhysicsController::setMargin(float collisionMargin)
+{
+ SumoPhysicsController::SetMargin(collisionMargin);
+}
+
+
+void KX_SumoPhysicsController::setOrientation(const MT_Quaternion& orn)
+{
+ SumoPhysicsController::setOrientation(
+ orn[0],orn[1],orn[2],orn[3]);
+
+}
+void KX_SumoPhysicsController::getOrientation(MT_Quaternion& orn)
+{
+
+ float quat[4];
+
+ SumoPhysicsController::getOrientation(quat[0],quat[1],quat[2],quat[3]);
+
+ orn = MT_Quaternion(quat);
+
+}
+
+void KX_SumoPhysicsController::setPosition(const MT_Point3& pos)
+{
+ SumoPhysicsController::setPosition(pos[0],pos[1],pos[2]);
+
+}
+
+void KX_SumoPhysicsController::setScaling(const MT_Vector3& scaling)
+{
+ SumoPhysicsController::setScaling(scaling[0],scaling[1],scaling[2]);
+
+}
+
+MT_Scalar KX_SumoPhysicsController::GetMass()
+{
+ return SumoPhysicsController::getMass();
+}
+
+MT_Vector3 KX_SumoPhysicsController::getReactionForce()
+{
+ float force[3];
+ SumoPhysicsController::getReactionForce(force[0],force[1],force[2]);
+ return MT_Vector3(force);
+
+}
+
+void KX_SumoPhysicsController::setRigidBody(bool rigid)
+{
+ SumoPhysicsController::setRigidBody(rigid);
+
+}
+
+
+KX_SumoPhysicsController::~KX_SumoPhysicsController()
+{
+
+
+}
+
+
+#endif//USE_SUMO_SOLID
diff --git a/source/gameengine/Ketsji/KX_SumoPhysicsController.h b/source/gameengine/Ketsji/KX_SumoPhysicsController.h
new file mode 100644
index 00000000000..d214091a8c6
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SumoPhysicsController.h
@@ -0,0 +1,112 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_SUMOPHYSICSCONTROLLER_H
+#define __KX_SUMOPHYSICSCONTROLLER_H
+
+#include "PHY_IPhysicsController.h"
+
+/**
+ Physics Controller, a special kind of Scene Graph Transformation Controller.
+ It get's callbacks from Sumo in case a transformation change took place.
+ Each time the scene graph get's updated, the controller get's a chance
+ in the 'Update' method to reflect changed.
+*/
+
+#include "SumoPhysicsController.h"
+#include "KX_IPhysicsController.h"
+
+class KX_SumoPhysicsController : public KX_IPhysicsController,
+ public SumoPhysicsController
+
+{
+
+
+public:
+ KX_SumoPhysicsController(
+ class SM_Scene* sumoScene,
+ class SM_Object* sumoObj,
+ class PHY_IMotionState* motionstate
+ ,bool dyna)
+ : KX_IPhysicsController(dyna,NULL) ,
+ SumoPhysicsController(sumoScene,/*solidscene,*/sumoObj,motionstate,dyna)
+ {
+ };
+ virtual ~KX_SumoPhysicsController();
+
+ void applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse);
+ virtual void SetObject (SG_IObject* object);
+ virtual void setMargin (float collisionMargin);
+
+ void RelativeTranslate(const MT_Vector3& dloc,bool local);
+ void RelativeRotate(const MT_Matrix3x3& drot,bool local);
+ void ApplyTorque(const MT_Vector3& torque,bool local);
+ void ApplyForce(const MT_Vector3& force,bool local);
+ MT_Vector3 GetLinearVelocity();
+ MT_Vector3 GetVelocity(const MT_Point3& pos);
+ void SetAngularVelocity(const MT_Vector3& ang_vel,bool local);
+ void SetLinearVelocity(const MT_Vector3& lin_vel,bool local);
+ void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ);
+
+
+ void SuspendDynamics();
+ void RestoreDynamics();
+ virtual void getOrientation(MT_Quaternion& orn);
+ virtual void setOrientation(const MT_Quaternion& orn);
+
+ virtual void setPosition(const MT_Point3& pos);
+ virtual void setScaling(const MT_Vector3& scaling);
+ virtual MT_Scalar GetMass();
+ virtual MT_Vector3 getReactionForce();
+ virtual void setRigidBody(bool rigid);
+
+
+ virtual SG_Controller* GetReplica(class SG_Node* destnode);
+
+
+ void SetSumoTransform(bool nondynaonly);
+ // todo: remove next line !
+ virtual void SetSimulatedTime(double time);
+
+ // call from scene graph to update
+ virtual bool Update(double time);
+
+ void
+ SetOption(
+ int option,
+ int value
+ ){
+ // intentionally empty
+ };
+};
+
+#endif //__KX_SUMOPHYSICSCONTROLLER_H
+
diff --git a/source/gameengine/Ketsji/KX_TimeCategoryLogger.cpp b/source/gameengine/Ketsji/KX_TimeCategoryLogger.cpp
new file mode 100644
index 00000000000..61bd0385972
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_TimeCategoryLogger.cpp
@@ -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 *****
+ */
+
+#include "KX_TimeCategoryLogger.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_TimeCategoryLogger::KX_TimeCategoryLogger(unsigned int maxNumMeasurements)
+: m_maxNumMeasurements(maxNumMeasurements)
+{
+}
+
+
+KX_TimeCategoryLogger::~KX_TimeCategoryLogger(void)
+{
+ DisposeLoggers();
+}
+
+
+void KX_TimeCategoryLogger::SetMaxNumMeasurements(unsigned int maxNumMeasurements)
+{
+ KX_TimeLoggerMap::iterator it;
+ for (it = m_loggers.begin(); it != m_loggers.end(); it++) {
+ it->second->SetMaxNumMeasurements(maxNumMeasurements);
+ }
+ m_maxNumMeasurements = maxNumMeasurements;
+}
+
+
+unsigned int KX_TimeCategoryLogger::GetMaxNumMeasurements(void) const
+{
+ return m_maxNumMeasurements;
+}
+
+
+void KX_TimeCategoryLogger::AddCategory(TimeCategory tc)
+{
+ // Only add if not already present
+ if (m_loggers.find(tc) == m_loggers.end()) {
+ KX_TimeLogger* logger = new KX_TimeLogger(m_maxNumMeasurements);
+ //assert(logger);
+ m_loggers.insert(KX_TimeLoggerMap::value_type(tc, logger));
+ }
+}
+
+
+void KX_TimeCategoryLogger::StartLog(TimeCategory tc, double now, bool endOtherCategories)
+{
+ if (endOtherCategories) {
+ KX_TimeLoggerMap::iterator it;
+ for (it = m_loggers.begin(); it != m_loggers.end(); it++) {
+ if (it->first != tc) {
+ it->second->EndLog(now);
+ }
+ }
+ }
+ //assert(m_loggers[tc] != m_loggers.end());
+ m_loggers[tc]->StartLog(now);
+}
+
+
+void KX_TimeCategoryLogger::EndLog(TimeCategory tc, double now)
+{
+ //assert(m_loggers[tc] != m_loggers.end());
+ m_loggers[tc]->EndLog(now);
+}
+
+
+void KX_TimeCategoryLogger::EndLog(double now)
+{
+ KX_TimeLoggerMap::iterator it;
+ for (it = m_loggers.begin(); it != m_loggers.end(); it++) {
+ it->second->EndLog(now);
+ }
+}
+
+
+void KX_TimeCategoryLogger::NextMeasurement(double now)
+{
+ KX_TimeLoggerMap::iterator it;
+ for (it = m_loggers.begin(); it != m_loggers.end(); it++) {
+ it->second->NextMeasurement(now);
+ }
+}
+
+
+double KX_TimeCategoryLogger::GetAverage(TimeCategory tc)
+{
+ //assert(m_loggers[tc] != m_loggers.end());
+ return m_loggers[tc]->GetAverage();
+}
+
+
+double KX_TimeCategoryLogger::GetAverage(void)
+{
+ double time = 0.;
+
+ KX_TimeLoggerMap::iterator it;
+ for (it = m_loggers.begin(); it != m_loggers.end(); it++) {
+ time += it->second->GetAverage();
+ }
+
+ return time;
+}
+
+
+void KX_TimeCategoryLogger::DisposeLoggers(void)
+{
+ KX_TimeLoggerMap::iterator it;
+ for (it = m_loggers.begin(); it != m_loggers.end(); it++) {
+ delete it->second;
+ }
+}
+
diff --git a/source/gameengine/Ketsji/KX_TimeCategoryLogger.h b/source/gameengine/Ketsji/KX_TimeCategoryLogger.h
new file mode 100644
index 00000000000..b96b1202f4c
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_TimeCategoryLogger.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 __KX_TIME_CATEGORY_LOGGER_H
+#define __KX_TIME_CATEGORY_LOGGER_H
+
+#ifdef WIN32
+#pragma warning (disable:4786) // suppress stl-MSVC debug info warning
+#endif
+
+#include <map>
+
+#include "KX_TimeLogger.h"
+
+/**
+ * Stores and manages time measurements by category.
+ * Categories can be added dynamically.
+ * Average measurements can be established for each separate category
+ * or for all categories together.
+ */
+class KX_TimeCategoryLogger {
+public:
+ typedef int TimeCategory;
+
+ /**
+ * Constructor.
+ * @param maxNumMesasurements Maximum number of measurements stored (> 1).
+ */
+ KX_TimeCategoryLogger(unsigned int maxNumMeasurements = 10);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KX_TimeCategoryLogger(void);
+
+ /**
+ * Changes the maximum number of measurements that can be stored.
+ */
+ virtual void SetMaxNumMeasurements(unsigned int maxNumMeasurements);
+
+ /**
+ * Changes the maximum number of measurements that can be stored.
+ */
+ virtual unsigned int GetMaxNumMeasurements(void) const;
+
+ /**
+ * Adds a category.
+ * @param category The new category.
+ */
+ virtual void AddCategory(TimeCategory tc);
+
+ /**
+ * Starts logging in current measurement for the given category.
+ * @param tc The category to log to.
+ * @param now The current time.
+ * @param endOtherCategories Whether to stop logging to other categories.
+ */
+ virtual void StartLog(TimeCategory tc, double now, bool endOtherCategories = true);
+
+ /**
+ * End logging in current measurement for the given category.
+ * @param tc The category to log to.
+ * @param now The current time.
+ */
+ virtual void EndLog(TimeCategory tc, double now);
+
+ /**
+ * End logging in current measurement for all categories.
+ * @param now The current time.
+ */
+ virtual void EndLog(double now);
+
+ /**
+ * Logs time in next measurement.
+ * @param now The current time.
+ */
+ virtual void NextMeasurement(double now);
+
+ /**
+ * Returns average of all but the current measurement time.
+ * @return The average of all but the current measurement.
+ */
+ virtual double GetAverage(TimeCategory tc);
+
+ /**
+ * Returns average for grand total.
+ */
+ virtual double GetAverage(void);
+
+protected:
+ /**
+ * Disposes loggers.
+ */
+ virtual void DisposeLoggers(void);
+
+ /** Storage for the loggers. */
+ typedef std::map<TimeCategory, KX_TimeLogger*> KX_TimeLoggerMap;
+ KX_TimeLoggerMap m_loggers;
+ /** Maximum number of measurements. */
+ unsigned int m_maxNumMeasurements;
+
+};
+
+#endif // __KX_TIME_CATEGORY_LOGGER_H
+
diff --git a/source/gameengine/Ketsji/KX_TimeLogger.cpp b/source/gameengine/Ketsji/KX_TimeLogger.cpp
new file mode 100644
index 00000000000..766c541b4fc
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_TimeLogger.cpp
@@ -0,0 +1,121 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_TimeLogger.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_TimeLogger::KX_TimeLogger(unsigned int maxNumMeasurements) :
+ m_maxNumMeasurements(maxNumMeasurements),
+ m_logStart(0),
+ m_logging(false)
+{
+}
+
+
+KX_TimeLogger::~KX_TimeLogger(void)
+{
+}
+
+
+void KX_TimeLogger::SetMaxNumMeasurements(unsigned int maxNumMeasurements)
+{
+ if ((m_maxNumMeasurements != maxNumMeasurements) && maxNumMeasurements) {
+ // Actual removing is done in NextMeasurement()
+ m_maxNumMeasurements = maxNumMeasurements;
+ }
+}
+
+
+unsigned int KX_TimeLogger::GetMaxNumMeasurements(void) const
+{
+ return m_maxNumMeasurements;
+}
+
+
+void KX_TimeLogger::StartLog(double now)
+{
+ if (!m_logging) {
+ m_logging = true;
+ m_logStart = now;
+ }
+}
+
+
+void KX_TimeLogger::EndLog(double now)
+{
+ if (m_logging) {
+ m_logging = false;
+ double time = now - m_logStart;
+ if (m_measurements.size() > 0) {
+ m_measurements[0] += time;
+ }
+ }
+}
+
+
+void KX_TimeLogger::NextMeasurement(double now)
+{
+ // End logging to current measurement
+ EndLog(now);
+
+ // Add a new measurement at the front
+ double m = 0.;
+ m_measurements.push_front(m);
+
+ // Remove measurement if we grow beyond the maximum size
+ if ((m_measurements.size()) > m_maxNumMeasurements) {
+ while (m_measurements.size() > m_maxNumMeasurements) {
+ m_measurements.pop_back();
+ }
+ }
+}
+
+
+
+double KX_TimeLogger::GetAverage(void) const
+{
+ double avg = 0.;
+
+ unsigned int numMeasurements = m_measurements.size();
+ if (numMeasurements > 1) {
+ for (unsigned int i = 1; i < numMeasurements; i++) {
+ avg += m_measurements[i];
+ }
+ avg /= (float)numMeasurements - 1;
+ }
+
+ return avg;
+}
+
diff --git a/source/gameengine/Ketsji/KX_TimeLogger.h b/source/gameengine/Ketsji/KX_TimeLogger.h
new file mode 100644
index 00000000000..ab3d721e7d2
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_TimeLogger.h
@@ -0,0 +1,107 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_TIME_LOGGER_H
+#define __KX_TIME_LOGGER_H
+
+#ifdef WIN32
+#pragma warning (disable:4786) // suppress stl-MSVC debug info warning
+#endif
+
+#include <deque>
+
+/**
+ * Stores and manages time measurements.
+ */
+class KX_TimeLogger {
+public:
+ /**
+ * Constructor.
+ * @param maxNumMesasurements Maximum number of measurements stored (>1).
+ */
+ KX_TimeLogger(unsigned int maxNumMeasurements = 10);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KX_TimeLogger(void);
+
+ /**
+ * Changes the maximum number of measurements that can be stored.
+ */
+ virtual void SetMaxNumMeasurements(unsigned int maxNumMeasurements);
+
+ /**
+ * Changes the maximum number of measurements that can be stored.
+ */
+ virtual unsigned int GetMaxNumMeasurements(void) const;
+
+ /**
+ * Starts logging in current measurement.
+ * @param now The current time.
+ */
+ virtual void StartLog(double now);
+
+ /**
+ * End logging in current measurement.
+ * @param now The current time.
+ */
+ virtual void EndLog(double now);
+
+ /**
+ * Logs time in next measurement.
+ * @param now The current time.
+ */
+ virtual void NextMeasurement(double now);
+
+ /**
+ * Returns average of all but the current measurement.
+ * @return The average of all but the current measurement.
+ */
+ virtual double GetAverage(void) const;
+
+protected:
+ /** Storage for the measurements. */
+ std::deque<double> m_measurements;
+
+ /** Maximum number of measurements. */
+ unsigned int m_maxNumMeasurements;
+
+ /** Time at start of logging. */
+ double m_logStart;
+
+ /** State of logging. */
+ bool m_logging;
+};
+
+#endif // __KX_TIME_LOGGER_H
+
diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp
new file mode 100644
index 00000000000..4c999b0ed69
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp
@@ -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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "KX_TouchEventManager.h"
+#include "SCA_ISensor.h"
+#include "KX_TouchSensor.h"
+#include "KX_GameObject.h"
+#include "PHY_IPhysicsEnvironment.h"
+#include "PHY_IPhysicsController.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+KX_TouchEventManager::KX_TouchEventManager(class SCA_LogicManager* logicmgr,
+ PHY_IPhysicsEnvironment* physEnv)
+ : SCA_EventManager(TOUCH_EVENTMGR),
+ m_logicmgr(logicmgr),
+ m_physEnv(physEnv)
+{
+ //notm_scene->addTouchCallback(STATIC_RESPONSE, KX_TouchEventManager::collisionResponse, this);
+
+ //m_scene->addTouchCallback(OBJECT_RESPONSE, KX_TouchEventManager::collisionResponse, this);
+ //m_scene->addTouchCallback(SENSOR_RESPONSE, KX_TouchEventManager::collisionResponse, this);
+
+ m_physEnv->addTouchCallback(PHY_OBJECT_RESPONSE, KX_TouchEventManager::newCollisionResponse, this);
+ m_physEnv->addTouchCallback(PHY_SENSOR_RESPONSE, KX_TouchEventManager::newCollisionResponse, this);
+
+}
+
+bool KX_TouchEventManager::NewHandleCollision(void* object1, void* object2, const PHY_CollData *coll_data)
+{
+
+ PHY_IPhysicsController* obj1 = static_cast<PHY_IPhysicsController*>(object1);
+ PHY_IPhysicsController* obj2 = static_cast<PHY_IPhysicsController*>(object2);
+
+ m_newCollisions.insert(std::pair<PHY_IPhysicsController*, PHY_IPhysicsController*>(obj1, obj2));
+
+ return false;
+}
+
+
+bool KX_TouchEventManager::newCollisionResponse(void *client_data,
+ void *object1,
+ void *object2,
+ const PHY_CollData *coll_data)
+{
+ KX_TouchEventManager *touchmgr = (KX_TouchEventManager *) client_data;
+ touchmgr->NewHandleCollision(object1, object2, coll_data);
+ return false;
+}
+
+void KX_TouchEventManager::RegisterSensor(SCA_ISensor* sensor)
+{
+ KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(sensor);
+ m_sensors.push_back(touchsensor);
+
+ touchsensor->RegisterSumo(this);
+}
+
+
+
+void KX_TouchEventManager::EndFrame()
+{
+ vector<SCA_ISensor*>::iterator it;
+ for ( it = m_sensors.begin();
+ !(it==m_sensors.end());it++)
+ {
+ ((KX_TouchSensor*)*it)->EndFrame();
+
+ }
+}
+
+
+
+void KX_TouchEventManager::NextFrame()
+{
+ if (m_sensors.size() > 0)
+ {
+ vector<SCA_ISensor*>::iterator it;
+
+ for (it = m_sensors.begin();!(it==m_sensors.end());++it)
+ static_cast<KX_TouchSensor*>(*it)->SynchronizeTransform();
+
+ for (std::set<NewCollision>::iterator cit = m_newCollisions.begin(); cit != m_newCollisions.end(); ++cit)
+ {
+ PHY_IPhysicsController* ctrl1 = (*cit).first;
+// PHY_IPhysicsController* ctrl2 = (*cit).second;
+// KX_GameObject* gameOb1 = ctrl1->getClientInfo();
+// KX_GameObject* gameOb1 = ctrl1->getClientInfo();
+
+ KX_ClientObjectInfo *client_info = static_cast<KX_ClientObjectInfo *>(ctrl1->getNewClientInfo());
+
+ list<SCA_ISensor*>::iterator sit;
+ for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit)
+ static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).first, (*cit).second, NULL);
+
+ client_info = static_cast<KX_ClientObjectInfo *>((*cit).second->getNewClientInfo());
+ for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit)
+ static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).second, (*cit).first, NULL);
+ }
+
+ m_newCollisions.clear();
+
+ for (it = m_sensors.begin();!(it==m_sensors.end());++it)
+ (*it)->Activate(m_logicmgr,NULL);
+ }
+}
+
+
+
+void KX_TouchEventManager::RemoveSensor(class SCA_ISensor* sensor)
+{
+ std::vector<SCA_ISensor*>::iterator i =
+ std::find(m_sensors.begin(), m_sensors.end(), sensor);
+ if (!(i == m_sensors.end()))
+ {
+ std::swap(*i, m_sensors.back());
+ m_sensors.pop_back();
+ }
+
+ // remove the sensor forever :)
+ SCA_EventManager::RemoveSensor(sensor);
+}
+
diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.h b/source/gameengine/Ketsji/KX_TouchEventManager.h
new file mode 100644
index 00000000000..21faceef799
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_TouchEventManager.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): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef __KX_TOUCHEVENTMANAGER
+#define __KX_TOUCHEVENTMANAGER
+
+
+#include "SCA_EventManager.h"
+#include "KX_TouchSensor.h"
+#include "KX_GameObject.h"
+
+#include <vector>
+#include <set>
+
+class SCA_ISensor;
+class PHY_IPhysicsEnvironment;
+
+class KX_TouchEventManager : public SCA_EventManager
+{
+ typedef std::pair<PHY_IPhysicsController*, PHY_IPhysicsController*> NewCollision;
+ class SCA_LogicManager* m_logicmgr;
+ PHY_IPhysicsEnvironment* m_physEnv;
+
+ std::set<NewCollision> m_newCollisions;
+
+
+ static bool newCollisionResponse(void *client_data,
+ void *object1,
+ void *object2,
+ const PHY_CollData *coll_data);
+
+ virtual bool NewHandleCollision(void* obj1,void* obj2,
+ const PHY_CollData * coll_data);
+
+
+
+
+
+public:
+ KX_TouchEventManager(class SCA_LogicManager* logicmgr,
+ PHY_IPhysicsEnvironment* physEnv);
+ virtual void NextFrame();
+ virtual void EndFrame();
+ virtual void RemoveSensor(class SCA_ISensor* sensor);
+ virtual void RegisterSensor(SCA_ISensor* sensor);
+ SCA_LogicManager* GetLogicManager() { return m_logicmgr;}
+ PHY_IPhysicsEnvironment *GetPhysicsEnvironment() { return m_physEnv; }
+
+};
+
+#endif //__KX_TOUCHEVENTMANAGER
+
diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp
new file mode 100644
index 00000000000..5b013e75e4e
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_TouchSensor.cpp
@@ -0,0 +1,397 @@
+/**
+ * Senses touch and collision events
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_TouchSensor.h"
+#include "SCA_EventManager.h"
+#include "SCA_LogicManager.h"
+#include "KX_GameObject.h"
+#include "KX_TouchEventManager.h"
+#include "KX_SumoPhysicsController.h"
+#include <iostream>
+#include "PHY_IPhysicsEnvironment.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+void KX_TouchSensor::SynchronizeTransform()
+{
+
+ if (m_physCtrl)
+ {
+
+ KX_GameObject* parent = ((KX_GameObject*)GetParent());
+ MT_Vector3 pos = parent->NodeGetWorldPosition();
+ MT_Quaternion orn = parent->NodeGetWorldOrientation().getRotation();
+ m_physCtrl->setPosition(pos.x(),pos.y(),pos.z());
+ m_physCtrl->setOrientation(orn.x(),orn.y(),orn.z(),orn.w());
+ m_physCtrl->calcXform();
+ }
+
+}
+
+
+void KX_TouchSensor::EndFrame() {
+ m_colliders->ReleaseAndRemoveAll();
+ m_bTriggered = false;
+}
+
+bool KX_TouchSensor::Evaluate(CValue* event)
+{
+ bool result = false;
+
+ if (m_bTriggered != m_bLastTriggered)
+ {
+ m_bLastTriggered = m_bTriggered;
+ if (!m_bTriggered)
+ m_hitObject = NULL;
+ result = true;
+ }
+
+ return result;
+}
+
+KX_TouchSensor::KX_TouchSensor(SCA_EventManager* eventmgr,KX_GameObject* gameobj,bool bFindMaterial,const STR_String& touchedpropname,PyTypeObject* T)
+:SCA_ISensor(gameobj,eventmgr,T),
+m_touchedpropname(touchedpropname),
+m_bFindMaterial(bFindMaterial),
+m_eventmgr(eventmgr),
+/*m_sumoObj(sumoObj),*/
+m_bCollision(false),
+m_bTriggered(false),
+m_bLastTriggered(false)
+{
+// KX_TouchEventManager* touchmgr = (KX_TouchEventManager*) eventmgr;
+// m_resptable = touchmgr->GetResponseTable();
+
+// m_solidHandle = m_sumoObj->getObjectHandle();
+
+ m_hitObject = NULL;
+ m_colliders = new CListValue();
+
+ KX_ClientObjectInfo *client_info = gameobj->getClientInfo();
+ client_info->m_gameobject = gameobj;
+ client_info->m_auxilary_info = NULL;
+ client_info->m_sensors.push_back(this);
+
+ m_physCtrl = dynamic_cast<PHY_IPhysicsController*>(gameobj->GetPhysicsController());
+ MT_assert( !gameobj->GetPhysicsController() || m_physCtrl );
+}
+
+
+KX_TouchSensor::~KX_TouchSensor()
+{
+ //DT_ClearObjectResponse(m_resptable,m_solidHandle);
+ m_colliders->Release();
+}
+
+CValue* KX_TouchSensor::GetReplica()
+{
+ KX_TouchSensor* replica = new KX_TouchSensor(*this);
+ replica->m_colliders = new CListValue();
+ replica->m_bCollision = false;
+ replica->m_bTriggered= false;
+ replica->m_hitObject = NULL;
+ replica->m_bLastTriggered = false;
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+}
+
+void KX_TouchSensor::ReParent(SCA_IObject* parent)
+{
+ KX_GameObject *gameobj = static_cast<KX_GameObject *>(parent);
+ PHY_IPhysicsController *sphy = dynamic_cast<PHY_IPhysicsController*>(((KX_GameObject*)parent)->GetPhysicsController());
+ if (sphy)
+ m_physCtrl = sphy;
+
+// m_solidHandle = m_sumoObj->getObjectHandle();
+ KX_ClientObjectInfo *client_info = gameobj->getClientInfo();
+ client_info->m_gameobject = gameobj;
+ client_info->m_auxilary_info = NULL;
+
+ client_info->m_sensors.push_back(this);
+ SCA_ISensor::ReParent(parent);
+}
+
+void KX_TouchSensor::RegisterSumo(KX_TouchEventManager *touchman)
+{
+ if (m_physCtrl)
+ {
+ touchman->GetPhysicsEnvironment()->requestCollisionCallback(m_physCtrl);
+ // collision
+ // Deprecated
+
+ }
+}
+
+bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_CollData* colldata)
+{
+// KX_TouchEventManager* toucheventmgr = (KX_TouchEventManager*)m_eventmgr;
+ KX_GameObject* parent = (KX_GameObject*)GetParent();
+
+ // need the mapping from PHY_IPhysicsController to gameobjects now
+
+ KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*> (object1 == m_physCtrl?
+ ((PHY_IPhysicsController*)object2)->getNewClientInfo():
+ ((PHY_IPhysicsController*)object1)->getNewClientInfo());
+
+ KX_GameObject* gameobj = ( client_info ?
+ client_info->m_gameobject :
+ NULL);
+
+ if (gameobj && (gameobj != parent) && client_info->isActor())
+ {
+ if (!m_colliders->SearchValue(gameobj))
+ m_colliders->Add(gameobj->AddRef());
+
+ bool found = m_touchedpropname.IsEmpty();
+ if (!found)
+ {
+ if (m_bFindMaterial)
+ {
+ if (client_info->m_auxilary_info)
+ {
+ found = (m_touchedpropname == STR_String((char*)client_info->m_auxilary_info));
+ }
+ } else
+ {
+ found = (gameobj->GetProperty(m_touchedpropname) != NULL);
+ }
+ }
+ if (found)
+ {
+ m_bTriggered = true;
+ m_hitObject = gameobj;
+ //printf("KX_TouchSensor::HandleCollision\n");
+ }
+
+ }
+ return DT_CONTINUE;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_TouchSensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_TouchSensor",
+ sizeof(KX_TouchSensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_TouchSensor::Parents[] = {
+ &KX_TouchSensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_TouchSensor::Methods[] = {
+ {"setProperty",
+ (PyCFunction) KX_TouchSensor::sPySetProperty, METH_VARARGS, SetProperty_doc},
+ {"getProperty",
+ (PyCFunction) KX_TouchSensor::sPyGetProperty, METH_VARARGS, GetProperty_doc},
+ {"getHitObject",
+ (PyCFunction) KX_TouchSensor::sPyGetHitObject, METH_VARARGS, GetHitObject_doc},
+ {"getHitObjectList",
+ (PyCFunction) KX_TouchSensor::sPyGetHitObjectList, METH_VARARGS, GetHitObjectList_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* KX_TouchSensor::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_ISensor);
+}
+
+/* Python API */
+
+/* 1. setProperty */
+char KX_TouchSensor::SetProperty_doc[] =
+"setProperty(name)\n"
+"\t- name: string\n"
+"\tSet the property or material to collide with. Use\n"
+"\tsetTouchMaterial() to switch between properties and\n"
+"\tmaterials.";
+PyObject* KX_TouchSensor::PySetProperty(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ char *nameArg;
+ if (!PyArg_ParseTuple(args, "s", &nameArg)) {
+ return NULL;
+ }
+
+ CValue* prop = GetParent()->FindIdentifier(nameArg);
+
+ if (!prop->IsError()) {
+ m_touchedpropname = nameArg;
+ prop->Release();
+ } else {
+ ; /* not found ... */
+ }
+
+ Py_Return;
+}
+/* 2. getProperty */
+char KX_TouchSensor::GetProperty_doc[] =
+"getProperty(name)\n"
+"\tReturns the property or material to collide with. Use\n"
+"\tgetTouchMaterial() to find out whether this sensor\n"
+"\tlooks for properties or materials.";
+PyObject* KX_TouchSensor::PyGetProperty(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return PyString_FromString(m_touchedpropname);
+}
+
+char KX_TouchSensor::GetHitObject_doc[] =
+"getHitObject()\n"
+;
+PyObject* KX_TouchSensor::PyGetHitObject(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ /* to do: do Py_IncRef if the object is already known in Python */
+ /* otherwise, this leaks memory */
+ if (m_hitObject)
+ {
+ return m_hitObject->AddRef();
+ }
+ Py_Return;
+}
+
+char KX_TouchSensor::GetHitObjectList_doc[] =
+"getHitObjectList()\n"
+"\tReturn a list of the objects this object collided with,\n"
+"\tbut only those matching the property/material condition.\n";
+PyObject* KX_TouchSensor::PyGetHitObjectList(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ /* to do: do Py_IncRef if the object is already known in Python */
+ /* otherwise, this leaks memory */
+
+ if ( m_touchedpropname.IsEmpty() ) {
+ return m_colliders->AddRef();
+ } else {
+ CListValue* newList = new CListValue();
+ int i = 0;
+ while (i < m_colliders->GetCount()) {
+ if (m_bFindMaterial) {
+ /* need to associate the CValues from the list to material
+ * names. The collider list _should_ contains only
+ * KX_GameObjects. I am loathe to cast them, though... The
+ * material name must be retrieved from Sumo. To a Sumo
+ * object, a client-info block is attached. This block
+ * contains the material name.
+ * - this also doesn't work (obviously) for multi-materials...
+ */
+ KX_GameObject* gameob = (KX_GameObject*) m_colliders->GetValue(i);
+ PHY_IPhysicsController* spc = dynamic_cast<PHY_IPhysicsController*>(gameob->GetPhysicsController());
+
+ if (spc) {
+ KX_ClientObjectInfo* cl_inf = static_cast<KX_ClientObjectInfo*>(spc->getNewClientInfo());
+
+ if (m_touchedpropname == ((char*)cl_inf->m_auxilary_info)) {
+ newList->Add(m_colliders->GetValue(i)->AddRef());
+ }
+ }
+
+ } else {
+ CValue* val = m_colliders->GetValue(i)->FindIdentifier(m_touchedpropname);
+ if (!val->IsError()) {
+ newList->Add(m_colliders->GetValue(i)->AddRef());
+ val->Release();
+ }
+ }
+
+ i++;
+ }
+ return newList->AddRef();
+ }
+
+}
+
+/* 5. getTouchMaterial */
+char KX_TouchSensor::GetTouchMaterial_doc[] =
+"getTouchMaterial()\n"
+"\tReturns KX_TRUE if this sensor looks for a specific material,\n"
+"\tKX_FALSE if it looks for a specific property.\n" ;
+PyObject* KX_TouchSensor::PyGetTouchMaterial(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyInt_FromLong(m_bFindMaterial);
+}
+
+/* 6. setTouchMaterial */
+char KX_TouchSensor::SetTouchMaterial_doc[] =
+"setTouchMaterial(flag)\n"
+"\t- flag: KX_TRUE or KX_FALSE.\n"
+"\tSet flag to KX_TRUE to switch on positive pulse mode,\n"
+"\tKX_FALSE to switch off positive pulse mode.\n" ;
+PyObject* KX_TouchSensor::PySetTouchMaterial(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int pulseArg = 0;
+
+ if(!PyArg_ParseTuple(args, "i", &pulseArg)) {
+ return NULL;
+ }
+
+ m_bFindMaterial = pulseArg != 0;
+
+ Py_Return;
+}
+
+
+/* eof */
diff --git a/source/gameengine/Ketsji/KX_TouchSensor.h b/source/gameengine/Ketsji/KX_TouchSensor.h
new file mode 100644
index 00000000000..f1a2a26e822
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_TouchSensor.h
@@ -0,0 +1,125 @@
+/**
+ * Senses touch and collision events
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __KX_TOUCHSENSOR
+#define __KX_TOUCHSENSOR
+
+#include "SCA_ISensor.h"
+#include "ListValue.h"
+
+struct PHY_CollData;
+
+#include "KX_ClientObjectInfo.h"
+
+class KX_TouchEventManager;
+
+class KX_TouchSensor : public SCA_ISensor
+{
+protected:
+ Py_Header;
+
+ /**
+ * The sensor should only look for objects with this property.
+ */
+ STR_String m_touchedpropname;
+ bool m_bFindMaterial;
+ class SCA_EventManager* m_eventmgr;
+
+ class PHY_IPhysicsController* m_physCtrl;
+ class PHY_ResponseTable* m_responstTable;
+ class PHY_PhysicsController* m_responsObject;
+
+ bool m_bCollision;
+ bool m_bTriggered;
+ bool m_bLastTriggered;
+ SCA_IObject* m_hitObject;
+ class CListValue* m_colliders;
+
+public:
+ KX_TouchSensor(class SCA_EventManager* eventmgr,
+ class KX_GameObject* gameobj,
+ bool fFindMaterial,
+ const STR_String& touchedpropname,
+ PyTypeObject* T=&Type) ;
+ virtual ~KX_TouchSensor();
+
+ virtual CValue* GetReplica();
+ virtual void SynchronizeTransform();
+ virtual bool Evaluate(CValue* event);
+ virtual void ReParent(SCA_IObject* parent);
+
+ virtual void RegisterSumo(KX_TouchEventManager* touchman);
+
+// virtual DT_Bool HandleCollision(void* obj1,void* obj2,
+// const DT_CollData * coll_data);
+
+ virtual bool NewHandleCollision(void*obj1,void*obj2,const PHY_CollData* colldata);
+
+ PHY_PhysicsController* GetPhysicsController() { return m_responsObject;}
+
+
+ virtual bool IsPositiveTrigger() {
+ bool result = m_bTriggered;
+ if (m_invert) result = !result;
+ return result;
+ }
+
+
+ virtual void EndFrame();
+
+ // todo: put some info for collision maybe
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ /* 1. setProperty */
+ KX_PYMETHOD_DOC(KX_TouchSensor,SetProperty);
+ /* 2. getProperty */
+ KX_PYMETHOD_DOC(KX_TouchSensor,GetProperty);
+ /* 3. getHitObject */
+ KX_PYMETHOD_DOC(KX_TouchSensor,GetHitObject);
+ /* 4. getHitObject */
+ KX_PYMETHOD_DOC(KX_TouchSensor,GetHitObjectList);
+ /* 5. getTouchMaterial */
+ KX_PYMETHOD_DOC(KX_TouchSensor,GetTouchMaterial);
+ /* 6. setTouchMaterial */
+ KX_PYMETHOD_DOC(KX_TouchSensor,SetTouchMaterial);
+
+};
+
+#endif //__KX_TOUCHSENSOR
+
diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
new file mode 100644
index 00000000000..36f0d3c3b99
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
@@ -0,0 +1,532 @@
+//
+// Replace the mesh for this actuator's parent
+//
+// $Id$
+//
+// ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version. The Blender
+// Foundation also sells licenses for use in proprietary software under
+// the Blender License. See http://www.blender.org/BL/ for information
+// about this.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+// All rights reserved.
+//
+// The Original Code is: all of this file.
+//
+// Contributor(s): none yet.
+//
+// ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+// todo: not all trackflags / upflags are implemented/tested !
+// m_trackflag is used to determine the forward tracking direction
+// m_upflag for the up direction
+// normal situation is +y for forward, +z for up
+
+#include "MT_Scalar.h"
+#include "SCA_IActuator.h"
+#include "KX_TrackToActuator.h"
+#include "SCA_IScene.h"
+#include "SCA_LogicManager.h"
+#include <math.h>
+#include <iostream>
+#include "KX_GameObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+
+
+KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj,
+ SCA_IObject *ob,
+ int time,
+ bool allow3D,
+ int trackflag,
+ int upflag,
+ PyTypeObject* T)
+ :
+ SCA_IActuator(gameobj, T)
+{
+ m_time = time;
+ m_allow3D = allow3D;
+ m_object = ob;
+ m_trackflag = trackflag;
+ m_upflag = upflag;
+ m_parentobj = 0;
+
+ if (m_object){
+ KX_GameObject* curobj = (KX_GameObject*) GetParent();
+
+ m_parentobj = curobj->GetParent(); // check if the object is parented
+ if (m_parentobj) { // if so, store the initial local rotation
+ m_parentlocalmat = m_parentobj->GetSGNode()->GetLocalOrientation();
+ }
+ }
+
+} /* End of constructor */
+
+
+
+/* old function from Blender */
+MT_Matrix3x3 EulToMat3(float *eul)
+{
+ MT_Matrix3x3 mat;
+ float 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] = cj*ch;
+ mat[1][0] = sj*sc-cs;
+ mat[2][0] = sj*cc+ss;
+ mat[0][1] = cj*sh;
+ mat[1][1] = sj*ss+cc;
+ mat[2][1] = sj*cs-sc;
+ mat[0][2] = -sj;
+ mat[1][2] = cj*si;
+ mat[2][2] = cj*ci;
+
+ return mat;
+}
+
+
+
+/* old function from Blender */
+void Mat3ToEulOld(MT_Matrix3x3 mat, float *eul)
+{
+ MT_Scalar cy;
+
+ cy = sqrt(mat[0][0]*mat[0][0] + mat[0][1]*mat[0][1]);
+
+ if (cy > 16.0*FLT_EPSILON) {
+ eul[0] = atan2(mat[1][2], mat[2][2]);
+ eul[1] = atan2(-mat[0][2], cy);
+ eul[2] = atan2(mat[0][1], mat[0][0]);
+ } else {
+ eul[0] = atan2(-mat[2][1], mat[1][1]);
+ eul[1] = atan2(-mat[0][2], cy);
+ eul[2] = 0.0;
+ }
+}
+
+
+
+/* old function from Blender */
+void compatible_eulFast(float *eul, float *oldrot)
+{
+ float dx, dy, dz;
+
+ /* verschillen van ong 360 graden corrigeren */
+
+ dx= eul[0] - oldrot[0];
+ dy= eul[1] - oldrot[1];
+ dz= eul[2] - oldrot[2];
+
+ if( fabs(dx) > 5.1) {
+ if(dx > 0.0) eul[0] -= MT_2_PI; else eul[0]+= MT_2_PI;
+ }
+ if( fabs(dy) > 5.1) {
+ if(dy > 0.0) eul[1] -= MT_2_PI; else eul[1]+= MT_2_PI;
+ }
+ if( fabs(dz) > 5.1 ) {
+ if(dz > 0.0) eul[2] -= MT_2_PI; else eul[2]+= MT_2_PI;
+ }
+}
+
+
+
+MT_Matrix3x3 matrix3x3_interpol(MT_Matrix3x3 oldmat, MT_Matrix3x3 mat, int m_time)
+{
+ float eul[3], oldeul[3];
+
+ Mat3ToEulOld(oldmat, oldeul);
+ Mat3ToEulOld(mat, eul);
+ compatible_eulFast(eul, oldeul);
+
+ eul[0]= (m_time*oldeul[0] + eul[0])/(1.0+m_time);
+ eul[1]= (m_time*oldeul[1] + eul[1])/(1.0+m_time);
+ eul[2]= (m_time*oldeul[2] + eul[2])/(1.0+m_time);
+
+ return EulToMat3(eul);
+}
+
+
+
+KX_TrackToActuator::~KX_TrackToActuator()
+{
+ // there's nothing to be done here, really....
+} /* end of destructor */
+
+
+
+bool KX_TrackToActuator::Update(double curtime, bool frame)
+{
+ bool result = false;
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (bNegativeEvent)
+ {
+ // do nothing on negative events
+ }
+ else if (m_object)
+ {
+ KX_GameObject* curobj = (KX_GameObject*) GetParent();
+ MT_Vector3 dir = ((KX_GameObject*)m_object)->NodeGetWorldPosition() - curobj->NodeGetWorldPosition();
+ dir.normalize();
+ MT_Vector3 up(0,0,1);
+
+
+#ifdef DSADSA
+ switch (m_upflag)
+ {
+ case 0:
+ {
+ up = MT_Vector3(1.0,0,0);
+ break;
+ }
+ case 1:
+ {
+ up = MT_Vector3(0,1.0,0);
+ break;
+ }
+ case 2:
+ default:
+ {
+ up = MT_Vector3(0,0,1.0);
+ }
+ }
+#endif
+ if (m_allow3D)
+ {
+ up = (up - up.dot(dir) * dir).normalized();
+
+ }
+ else
+ {
+ dir = (dir - up.dot(dir)*up).normalized();
+ }
+
+ MT_Vector3 left;
+ MT_Matrix3x3 mat;
+
+ switch (m_trackflag)
+ {
+ case 0: // TRACK X
+ {
+ // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up
+ left = dir.normalized();
+ dir = (left.cross(up)).normalized();
+ mat.setValue (
+ left[0], dir[0],up[0],
+ left[1], dir[1],up[1],
+ left[2], dir[2],up[2]
+ );
+
+ break;
+ };
+ case 1: // TRACK Y
+ {
+ // (0.0 , 1.0 , 0.0 ) y direction is forward, z (0.0 , 0.0 , 1.0 ) up
+ left = (dir.cross(up)).normalized();
+ mat.setValue (
+ left[0], dir[0],up[0],
+ left[1], dir[1],up[1],
+ left[2], dir[2],up[2]
+ );
+
+ break;
+ }
+
+ case 2: // track Z
+ {
+ left = up.normalized();
+ up = dir.normalized();
+ dir = left;
+ left = (dir.cross(up)).normalized();
+ mat.setValue (
+ left[0], dir[0],up[0],
+ left[1], dir[1],up[1],
+ left[2], dir[2],up[2]
+ );
+ break;
+ }
+
+ case 3: // TRACK -X
+ {
+ // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up
+ left = -dir.normalized();
+ dir = -(left.cross(up)).normalized();
+ mat.setValue (
+ left[0], dir[0],up[0],
+ left[1], dir[1],up[1],
+ left[2], dir[2],up[2]
+ );
+
+ break;
+ };
+ case 4: // TRACK -Y
+ {
+ // (0.0 , -1.0 , 0.0 ) -y direction is forward, z (0.0 , 0.0 , 1.0 ) up
+ left = (-dir.cross(up)).normalized();
+ mat.setValue (
+ left[0], -dir[0],up[0],
+ left[1], -dir[1],up[1],
+ left[2], -dir[2],up[2]
+ );
+ break;
+ }
+ case 5: // track -Z
+ {
+ left = up.normalized();
+ up = -dir.normalized();
+ dir = left;
+ left = (dir.cross(up)).normalized();
+ mat.setValue (
+ left[0], dir[0],up[0],
+ left[1], dir[1],up[1],
+ left[2], dir[2],up[2]
+ );
+
+ break;
+ }
+
+ default:
+ {
+ // (1.0 , 0.0 , 0.0 ) -x direction is forward, z (0.0 , 0.0 , 1.0 ) up
+ left = -dir.normalized();
+ dir = -(left.cross(up)).normalized();
+ mat.setValue (
+ left[0], dir[0],up[0],
+ left[1], dir[1],up[1],
+ left[2], dir[2],up[2]
+ );
+ }
+ }
+
+ MT_Matrix3x3 oldmat;
+ oldmat= curobj->NodeGetWorldOrientation();
+
+ /* erwin should rewrite this! */
+ mat= matrix3x3_interpol(oldmat, mat, m_time);
+
+
+ if(m_parentobj){ // check if the model is parented and calculate the child transform
+
+ MT_Point3 localpos;
+ localpos = curobj->GetSGNode()->GetLocalPosition();
+ // Get the inverse of the parent matrix
+ MT_Matrix3x3 parentmatinv;
+ parentmatinv = m_parentobj->NodeGetWorldOrientation ().inverse ();
+ // transform the local coordinate system into the parents system
+ mat = parentmatinv * mat;
+ // append the initial parent local rotation matrix
+ mat = m_parentlocalmat * mat;
+
+ // set the models tranformation properties
+ curobj->NodeSetLocalOrientation(mat);
+ curobj->NodeSetLocalPosition(localpos);
+ curobj->UpdateTransform();
+ }
+ else
+ {
+ curobj->NodeSetLocalOrientation(mat);
+ }
+
+ result = true;
+ }
+
+ return result;
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_TrackToActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_TrackToActuator",
+ sizeof(KX_TrackToActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+
+PyParentObject KX_TrackToActuator::Parents[] = {
+ &KX_TrackToActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+
+PyMethodDef KX_TrackToActuator::Methods[] = {
+ {"setObject", (PyCFunction) KX_TrackToActuator::sPySetObject, METH_VARARGS, SetObject_doc},
+ {"getObject", (PyCFunction) KX_TrackToActuator::sPyGetObject, METH_VARARGS, GetObject_doc},
+ {"setTime", (PyCFunction) KX_TrackToActuator::sPySetTime, METH_VARARGS, SetTime_doc},
+ {"getTime", (PyCFunction) KX_TrackToActuator::sPyGetTime, METH_VARARGS, GetTime_doc},
+ {"setUse3D", (PyCFunction) KX_TrackToActuator::sPySetUse3D, METH_VARARGS, SetUse3D_doc},
+ {"getUse3D", (PyCFunction) KX_TrackToActuator::sPyGetUse3D, METH_VARARGS, GetUse3D_doc},
+ {NULL,NULL} //Sentinel
+};
+
+
+
+PyObject* KX_TrackToActuator::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_IActuator);
+}
+
+
+
+/* 1. setObject */
+char KX_TrackToActuator::SetObject_doc[] =
+"setObject(object)\n"
+"\t- object: string\n"
+"\tSet the object to track with the parent of this actuator.\n";
+PyObject* KX_TrackToActuator::PySetObject(PyObject* self, PyObject* args, PyObject* kwds) {
+ PyObject* gameobj;
+ if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj))
+ {
+ m_object = (SCA_IObject*)gameobj;
+
+ Py_Return;
+ }
+ PyErr_Clear();
+
+ char* objectname;
+ if (PyArg_ParseTuple(args, "s", &objectname))
+ {
+ m_object= static_cast<SCA_IObject*>(SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname)));
+
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+
+
+/* 2. getObject */
+char KX_TrackToActuator::GetObject_doc[] =
+"getObject()\n"
+"\tReturns the object to track with the parent of this actuator.\n";
+PyObject* KX_TrackToActuator::PyGetObject(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ if (!m_object)
+ Py_Return;
+
+ return PyString_FromString(m_object->GetName());
+}
+
+
+
+/* 3. setTime */
+char KX_TrackToActuator::SetTime_doc[] =
+"setTime(time)\n"
+"\t- time: integer\n"
+"\tSet the time in frames with which to delay the tracking motion.\n";
+PyObject* KX_TrackToActuator::PySetTime(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int timeArg;
+
+ if (!PyArg_ParseTuple(args, "i", &timeArg))
+ {
+ return NULL;
+ }
+
+ m_time= timeArg;
+
+ Py_Return;
+}
+
+
+
+/* 4.getTime */
+char KX_TrackToActuator::GetTime_doc[] =
+"getTime()\n"
+"\t- time: integer\n"
+"\tReturn the time in frames with which the tracking motion is delayed.\n";
+PyObject* KX_TrackToActuator::PyGetTime(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyInt_FromLong(m_time);
+}
+
+
+
+/* 5. getUse3D */
+char KX_TrackToActuator::GetUse3D_doc[] =
+"getUse3D()\n"
+"\tReturns 1 if the motion is allowed to extend in the z-direction.\n";
+PyObject* KX_TrackToActuator::PyGetUse3D(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyInt_FromLong(!(m_allow3D == 0));
+}
+
+
+
+/* 6. setUse3D */
+char KX_TrackToActuator::SetUse3D_doc[] =
+"setUse3D(value)\n"
+"\t- value: 0 or 1\n"
+"\tSet to 1 to allow the tracking motion to extend in the z-direction,\n"
+"\tset to 0 to lock the tracking motion to the x-y plane.\n";
+PyObject* KX_TrackToActuator::PySetUse3D(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ int boolArg;
+
+ if (!PyArg_ParseTuple(args, "i", &boolArg)) {
+ return NULL;
+ }
+
+ m_allow3D = !(boolArg == 0);
+
+ Py_Return;
+}
+
+/* eof */
diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.h b/source/gameengine/Ketsji/KX_TrackToActuator.h
new file mode 100644
index 00000000000..1d257da3f53
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_TrackToActuator.h
@@ -0,0 +1,93 @@
+//
+// Add object to the game world on action of this actuator
+//
+// $Id$
+//
+// ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version. The Blender
+// Foundation also sells licenses for use in proprietary software under
+// the Blender License. See http://www.blender.org/BL/ for information
+// about this.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// The Original Code is Copyright (C) 2001-2002 by 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 __KX_TrackToActuator
+#define __KX_TrackToActuator
+
+#include "SCA_IActuator.h"
+#include "SCA_IObject.h"
+#include "MT_Matrix3x3.h"
+#include "KX_GameObject.h"
+
+
+class KX_TrackToActuator : public SCA_IActuator
+{
+ Py_Header;
+ // Object reference. Actually, we use the object's 'life'
+ SCA_IObject* m_object;
+ // 3d toggle
+ bool m_allow3D;
+ // time field
+ int m_time;
+ int m_trackTime;
+ int m_trackflag;
+ int m_upflag;
+
+ MT_Matrix3x3 m_parentlocalmat;
+ KX_GameObject* m_parentobj;
+
+ public:
+ KX_TrackToActuator(SCA_IObject* gameobj, SCA_IObject *ob, int time,
+ bool threedee,int trackflag,int upflag, PyTypeObject* T=&Type);
+ virtual ~KX_TrackToActuator();
+ virtual CValue* GetReplica() {
+ KX_TrackToActuator* replica = new KX_TrackToActuator(*this);
+ replica->ProcessReplica();
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+ };
+
+ virtual bool Update(double curtime, bool frame);
+
+ /* Python part */
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ /* 1. setObject */
+ KX_PYMETHOD_DOC(KX_TrackToActuator,SetObject);
+ /* 2. getObject */
+ KX_PYMETHOD_DOC(KX_TrackToActuator,GetObject);
+ /* 3. setTime */
+ KX_PYMETHOD_DOC(KX_TrackToActuator,SetTime);
+ /* 4. getTime */
+ KX_PYMETHOD_DOC(KX_TrackToActuator,GetTime);
+ /* 5. getUse3D */
+ KX_PYMETHOD_DOC(KX_TrackToActuator,GetUse3D);
+ /* 6. setUse3D */
+ KX_PYMETHOD_DOC(KX_TrackToActuator,SetUse3D);
+
+}; /* end of class KX_TrackToActuator : public KX_EditObjectActuator */
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
new file mode 100644
index 00000000000..fba2ecc223b
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
@@ -0,0 +1,367 @@
+
+
+#include <Python.h>
+#include "KX_VehicleWrapper.h"
+#include "PHY_IPhysicsEnvironment.h"
+#include "PHY_IVehicle.h"
+#include "KX_PyMath.h"
+#include "KX_GameObject.h"
+#include "KX_MotionState.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_VehicleWrapper::KX_VehicleWrapper(
+ PHY_IVehicle* vehicle,
+ PHY_IPhysicsEnvironment* physenv,PyTypeObject *T) :
+ PyObjectPlus(T),
+ m_vehicle(vehicle),
+ m_physenv(physenv)
+{
+}
+
+KX_VehicleWrapper::~KX_VehicleWrapper()
+{
+ int numMotion = m_motionStates.size();
+ for (int i=0;i<numMotion;i++)
+ {
+ PHY_IMotionState* motionState = m_motionStates[i];
+ delete motionState;
+ }
+ m_motionStates.clear();
+}
+
+
+PyObject* KX_VehicleWrapper::PyAddWheel(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ PyObject* pylistPos,*pylistDir,*pylistAxleDir;
+ PyObject* wheelGameObject;
+ float suspensionRestLength,wheelRadius;
+ int hasSteering;
+
+
+ if (PyArg_ParseTuple(args,"OOOOffi",&wheelGameObject,&pylistPos,&pylistDir,&pylistAxleDir,&suspensionRestLength,&wheelRadius,&hasSteering))
+ {
+ KX_GameObject* gameOb = (KX_GameObject*) wheelGameObject;
+
+ PHY_IMotionState* motionState = new KX_MotionState(gameOb->GetSGNode());
+
+ MT_Vector3 attachPos,attachDir,attachAxle;
+ PyVecTo(pylistPos,attachPos);
+ PyVecTo(pylistDir,attachDir);
+ PyVecTo(pylistAxleDir,attachAxle);
+ PHY__Vector3 aPos,aDir,aAxle;
+ aPos[0] = attachPos[0];
+ aPos[1] = attachPos[1];
+ aPos[2] = attachPos[2];
+ aDir[0] = attachDir[0];
+ aDir[1] = attachDir[1];
+ aDir[2] = attachDir[2];
+ aAxle[0] = -attachAxle[0];//someone reverse some conventions inside Bullet (axle winding)
+ aAxle[1] = -attachAxle[1];
+ aAxle[2] = -attachAxle[2];
+
+ printf("attempt for addWheel: suspensionRestLength%f wheelRadius %f, hasSteering:%d\n",suspensionRestLength,wheelRadius,hasSteering);
+ m_vehicle->AddWheel(motionState,aPos,aDir,aAxle,suspensionRestLength,wheelRadius,hasSteering);
+
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+
+
+PyObject* KX_VehicleWrapper::PyGetWheelPosition(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+
+ int wheelIndex;
+
+ if (PyArg_ParseTuple(args,"i",&wheelIndex))
+ {
+ float position[3];
+ m_vehicle->GetWheelPosition(wheelIndex,position[0],position[1],position[2]);
+ MT_Vector3 pos(position[0],position[1],position[2]);
+ return PyObjectFrom(pos);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* KX_VehicleWrapper::PyGetWheelRotation(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int wheelIndex;
+ if (PyArg_ParseTuple(args,"i",&wheelIndex))
+ {
+ return PyFloat_FromDouble(m_vehicle->GetWheelRotation(wheelIndex));
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* KX_VehicleWrapper::PyGetWheelOrientationQuaternion(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int wheelIndex;
+ if (PyArg_ParseTuple(args,"i",&wheelIndex))
+ {
+ float orn[4];
+ m_vehicle->GetWheelOrientationQuaternion(wheelIndex,orn[0],orn[1],orn[2],orn[3]);
+ MT_Quaternion quatorn(orn[0],orn[1],orn[2],orn[3]);
+ MT_Matrix3x3 ornmat(quatorn);
+ return PyObjectFrom(ornmat);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+
+}
+
+
+PyObject* KX_VehicleWrapper::PyGetNumWheels(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyInt_FromLong(m_vehicle->GetNumWheels());
+}
+
+
+PyObject* KX_VehicleWrapper::PyGetConstraintId(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyInt_FromLong(m_vehicle->GetUserConstraintId());
+}
+
+
+
+PyObject* KX_VehicleWrapper::PyApplyEngineForce(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float force;
+ int wheelIndex;
+
+ if (PyArg_ParseTuple(args,"fi",&force,&wheelIndex))
+ {
+ force *= -1.f;//someone reverse some conventions inside Bullet (axle winding)
+ m_vehicle->ApplyEngineForce(force,wheelIndex);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* KX_VehicleWrapper::PySetTyreFriction(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float wheelFriction;
+ int wheelIndex;
+
+ if (PyArg_ParseTuple(args,"fi",&wheelFriction,&wheelIndex))
+ {
+ m_vehicle->SetWheelFriction(wheelFriction,wheelIndex);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* KX_VehicleWrapper::PySetSuspensionStiffness(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float suspensionStiffness;
+ int wheelIndex;
+
+ if (PyArg_ParseTuple(args,"fi",&suspensionStiffness,&wheelIndex))
+ {
+ m_vehicle->SetSuspensionStiffness(suspensionStiffness,wheelIndex);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* KX_VehicleWrapper::PySetSuspensionDamping(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float suspensionDamping;
+ int wheelIndex;
+
+ if (PyArg_ParseTuple(args,"fi",&suspensionDamping,&wheelIndex))
+ {
+ m_vehicle->SetSuspensionDamping(suspensionDamping,wheelIndex);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* KX_VehicleWrapper::PySetSuspensionCompression(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float suspensionCompression;
+ int wheelIndex;
+
+ if (PyArg_ParseTuple(args,"fi",&suspensionCompression,&wheelIndex))
+ {
+ m_vehicle->SetSuspensionCompression(suspensionCompression,wheelIndex);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* KX_VehicleWrapper::PySetRollInfluence(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float rollInfluence;
+ int wheelIndex;
+
+ if (PyArg_ParseTuple(args,"fi",&rollInfluence,&wheelIndex))
+ {
+ m_vehicle->SetRollInfluence(rollInfluence,wheelIndex);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+PyObject* KX_VehicleWrapper::PyApplyBraking(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float braking;
+ int wheelIndex;
+
+ if (PyArg_ParseTuple(args,"fi",&braking,&wheelIndex))
+ {
+ m_vehicle->ApplyBraking(braking,wheelIndex);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+
+
+PyObject* KX_VehicleWrapper::PySetSteeringValue(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float steeringValue;
+ int wheelIndex;
+
+ if (PyArg_ParseTuple(args,"fi",&steeringValue,&wheelIndex))
+ {
+ m_vehicle->SetSteeringValue(steeringValue,wheelIndex);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+PyObject* KX_VehicleWrapper::PyGetConstraintType(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ return PyInt_FromLong(m_vehicle->GetUserConstraintType());
+}
+
+
+
+
+
+//python specific stuff
+PyTypeObject KX_VehicleWrapper::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_VehicleWrapper",
+ sizeof(KX_VehicleWrapper),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_VehicleWrapper::Parents[] = {
+ &KX_VehicleWrapper::Type,
+ NULL
+};
+
+PyObject* KX_VehicleWrapper::_getattr(const STR_String& attr)
+{
+ //here you can search for existing data members (like mass,friction etc.)
+ _getattr_up(PyObjectPlus);
+}
+
+int KX_VehicleWrapper::_setattr(const STR_String& attr,PyObject* pyobj)
+{
+
+ PyTypeObject* type = pyobj->ob_type;
+ int result = 1;
+
+ if (type == &PyList_Type)
+ {
+ result = 0;
+ }
+ if (type == &PyFloat_Type)
+ {
+ result = 0;
+
+ }
+ if (type == &PyInt_Type)
+ {
+ result = 0;
+ }
+ if (type == &PyString_Type)
+ {
+ result = 0;
+ }
+ if (result)
+ result = PyObjectPlus::_setattr(attr,pyobj);
+ return result;
+};
+
+
+PyMethodDef KX_VehicleWrapper::Methods[] = {
+ {"addWheel",(PyCFunction) KX_VehicleWrapper::sPyAddWheel, METH_VARARGS},
+ {"getNumWheels",(PyCFunction) KX_VehicleWrapper::sPyGetNumWheels, METH_VARARGS},
+ {"getWheelOrientationQuaternion",(PyCFunction) KX_VehicleWrapper::sPyGetWheelOrientationQuaternion, METH_VARARGS},
+ {"getWheelRotation",(PyCFunction) KX_VehicleWrapper::sPyGetWheelRotation, METH_VARARGS},
+ {"getWheelPosition",(PyCFunction) KX_VehicleWrapper::sPyGetWheelPosition, METH_VARARGS},
+ {"getConstraintId",(PyCFunction) KX_VehicleWrapper::sPyGetConstraintId, METH_VARARGS},
+ {"getConstraintType",(PyCFunction) KX_VehicleWrapper::sPyGetConstraintType, METH_VARARGS},
+ {"setSteeringValue",(PyCFunction) KX_VehicleWrapper::sPySetSteeringValue, METH_VARARGS},
+ {"applyEngineForce",(PyCFunction) KX_VehicleWrapper::sPyApplyEngineForce, METH_VARARGS},
+ {"applyBraking",(PyCFunction) KX_VehicleWrapper::sPyApplyBraking, METH_VARARGS},
+
+ {"setTyreFriction",(PyCFunction) KX_VehicleWrapper::sPySetTyreFriction, METH_VARARGS},
+
+ {"setSuspensionStiffness",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionStiffness, METH_VARARGS},
+
+ {"setSuspensionDamping",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionDamping, METH_VARARGS},
+
+ {"setSuspensionCompression",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionCompression, METH_VARARGS},
+
+ {"setRollInfluence",(PyCFunction) KX_VehicleWrapper::sPySetRollInfluence, METH_VARARGS},
+
+ {NULL,NULL} //Sentinel
+};
+
diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.h b/source/gameengine/Ketsji/KX_VehicleWrapper.h
new file mode 100644
index 00000000000..b98369d401a
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_VehicleWrapper.h
@@ -0,0 +1,58 @@
+#ifndef KX_VEHICLE_WRAPPER
+#define KX_VEHICLE_WRAPPER
+
+#include "Value.h"
+#include "PHY_DynamicTypes.h"
+class PHY_IVehicle;
+class PHY_IMotionState;
+
+#include <vector>
+
+///Python interface to physics vehicles (primarily 4-wheel cars and 2wheel bikes)
+class KX_VehicleWrapper : public PyObjectPlus
+{
+ Py_Header;
+ virtual PyObject* _getattr(const STR_String& attr);
+ virtual int _setattr(const STR_String& attr, PyObject *value);
+
+ std::vector<PHY_IMotionState*> m_motionStates;
+
+public:
+ KX_VehicleWrapper(PHY_IVehicle* vehicle,class PHY_IPhysicsEnvironment* physenv,PyTypeObject *T = &Type);
+ virtual ~KX_VehicleWrapper ();
+ int getConstraintId();
+
+
+ KX_PYMETHOD(KX_VehicleWrapper,AddWheel);
+ KX_PYMETHOD(KX_VehicleWrapper,GetNumWheels);
+ KX_PYMETHOD(KX_VehicleWrapper,GetWheelOrientationQuaternion);
+ KX_PYMETHOD(KX_VehicleWrapper,GetWheelRotation);
+
+ KX_PYMETHOD(KX_VehicleWrapper,GetWheelPosition);
+
+ KX_PYMETHOD(KX_VehicleWrapper,GetConstraintId);
+ KX_PYMETHOD(KX_VehicleWrapper,GetConstraintType);
+
+ KX_PYMETHOD(KX_VehicleWrapper,SetSteeringValue);
+
+ KX_PYMETHOD(KX_VehicleWrapper,ApplyEngineForce);
+
+ KX_PYMETHOD(KX_VehicleWrapper,ApplyBraking);
+
+ KX_PYMETHOD(KX_VehicleWrapper,SetTyreFriction);
+
+ KX_PYMETHOD(KX_VehicleWrapper,SetSuspensionStiffness);
+
+ KX_PYMETHOD(KX_VehicleWrapper,SetSuspensionDamping);
+
+ KX_PYMETHOD(KX_VehicleWrapper,SetSuspensionCompression);
+
+ KX_PYMETHOD(KX_VehicleWrapper,SetRollInfluence);
+
+
+private:
+ PHY_IVehicle* m_vehicle;
+ PHY_IPhysicsEnvironment* m_physenv;
+};
+
+#endif //KX_VEHICLE_WRAPPER
diff --git a/source/gameengine/Ketsji/KX_VertexProxy.cpp b/source/gameengine/Ketsji/KX_VertexProxy.cpp
new file mode 100644
index 00000000000..9c5f3f611b6
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_VertexProxy.cpp
@@ -0,0 +1,440 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "KX_VertexProxy.h"
+#include "KX_MeshProxy.h"
+#include "RAS_TexVert.h"
+
+#include "KX_PyMath.h"
+
+PyTypeObject KX_VertexProxy::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_VertexProxy",
+ sizeof(KX_VertexProxy),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_VertexProxy::Parents[] = {
+ &KX_VertexProxy::Type,
+ &SCA_IObject::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_VertexProxy::Methods[] = {
+{"getXYZ", (PyCFunction)KX_VertexProxy::sPyGetXYZ,METH_VARARGS},
+{"setXYZ", (PyCFunction)KX_VertexProxy::sPySetXYZ,METH_VARARGS},
+{"getUV", (PyCFunction)KX_VertexProxy::sPyGetUV,METH_VARARGS},
+{"setUV", (PyCFunction)KX_VertexProxy::sPySetUV,METH_VARARGS},
+
+{"getUV2", (PyCFunction)KX_VertexProxy::sPyGetUV2,METH_VARARGS},
+{"setUV2", (PyCFunction)KX_VertexProxy::sPySetUV2,METH_VARARGS},
+
+{"getRGBA", (PyCFunction)KX_VertexProxy::sPyGetRGBA,METH_VARARGS},
+{"setRGBA", (PyCFunction)KX_VertexProxy::sPySetRGBA,METH_VARARGS},
+{"getNormal", (PyCFunction)KX_VertexProxy::sPyGetNormal,METH_VARARGS},
+{"setNormal", (PyCFunction)KX_VertexProxy::sPySetNormal,METH_VARARGS},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject*
+KX_VertexProxy::_getattr(const STR_String& attr)
+{
+ if (attr == "XYZ")
+ return PyObjectFrom(MT_Vector3(m_vertex->getLocalXYZ()));
+
+ if (attr == "UV")
+ return PyObjectFrom(MT_Point2(m_vertex->getUV1()));
+
+ if (attr == "colour" || attr == "color")
+ {
+ const unsigned char *colp = m_vertex->getRGBA();
+ MT_Vector4 color(colp[0], colp[1], colp[2], colp[3]);
+ color /= 255.0;
+ return PyObjectFrom(color);
+ }
+
+ if (attr == "normal")
+ {
+ return PyObjectFrom(MT_Vector3(m_vertex->getNormal()));
+ }
+
+ // pos
+ if (attr == "x")
+ return PyFloat_FromDouble(m_vertex->getLocalXYZ()[0]);
+ if (attr == "y")
+ return PyFloat_FromDouble(m_vertex->getLocalXYZ()[1]);
+ if (attr == "z")
+ return PyFloat_FromDouble(m_vertex->getLocalXYZ()[2]);
+
+ // Col
+ if (attr == "r")
+ return PyFloat_FromDouble(m_vertex->getRGBA()[0]/255.0);
+ if (attr == "g")
+ return PyFloat_FromDouble(m_vertex->getRGBA()[1]/255.0);
+ if (attr == "b")
+ return PyFloat_FromDouble(m_vertex->getRGBA()[2]/255.0);
+ if (attr == "a")
+ return PyFloat_FromDouble(m_vertex->getRGBA()[3]/255.0);
+
+ // UV
+ if (attr == "u")
+ return PyFloat_FromDouble(m_vertex->getUV1()[0]);
+ if (attr == "v")
+ return PyFloat_FromDouble(m_vertex->getUV1()[1]);
+
+ _getattr_up(SCA_IObject);
+}
+
+int KX_VertexProxy::_setattr(const STR_String& attr, PyObject *pyvalue)
+{
+ if (PySequence_Check(pyvalue))
+ {
+ if (attr == "XYZ")
+ {
+ MT_Point3 vec;
+ if (PyVecTo(pyvalue, vec))
+ {
+ m_vertex->SetXYZ(vec);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+ return 1;
+ }
+
+ if (attr == "UV")
+ {
+ MT_Point2 vec;
+ if (PyVecTo(pyvalue, vec))
+ {
+ m_vertex->SetUV(vec);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+ return 1;
+ }
+
+ if (attr == "colour" || attr == "color")
+ {
+ MT_Vector4 vec;
+ if (PyVecTo(pyvalue, vec))
+ {
+ m_vertex->SetRGBA(vec);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+ return 1;
+ }
+
+ if (attr == "normal")
+ {
+ MT_Vector3 vec;
+ if (PyVecTo(pyvalue, vec))
+ {
+ m_vertex->SetNormal(vec);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+ return 1;
+ }
+ }
+
+ if (PyFloat_Check(pyvalue))
+ {
+ float val = PyFloat_AsDouble(pyvalue);
+ // pos
+ MT_Point3 pos(m_vertex->getLocalXYZ());
+ if (attr == "x")
+ {
+ pos.x() = val;
+ m_vertex->SetXYZ(pos);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+
+ if (attr == "y")
+ {
+ pos.y() = val;
+ m_vertex->SetXYZ(pos);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+
+ if (attr == "z")
+ {
+ pos.z() = val;
+ m_vertex->SetXYZ(pos);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+
+ // uv
+ MT_Point2 uv = m_vertex->getUV1();
+ if (attr == "u")
+ {
+ uv[0] = val;
+ m_vertex->SetUV(uv);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+
+ if (attr == "v")
+ {
+ uv[1] = val;
+ m_vertex->SetUV(uv);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+
+ // uv
+ MT_Point2 uv2 = m_vertex->getUV2();
+ if (attr == "u2")
+ {
+ uv[0] = val;
+ m_vertex->SetUV2(uv);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+
+ if (attr == "v2")
+ {
+ uv[1] = val;
+ m_vertex->SetUV2(uv);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+
+ // col
+ unsigned int icol = *((const unsigned int *)m_vertex->getRGBA());
+ unsigned char *cp = (unsigned char*) &icol;
+ val *= 255.0;
+ if (attr == "r")
+ {
+ cp[0] = (unsigned char) val;
+ m_vertex->SetRGBA(icol);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+ if (attr == "g")
+ {
+ cp[1] = (unsigned char) val;
+ m_vertex->SetRGBA(icol);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+ if (attr == "b")
+ {
+ cp[2] = (unsigned char) val;
+ m_vertex->SetRGBA(icol);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+ if (attr == "a")
+ {
+ cp[3] = (unsigned char) val;
+ m_vertex->SetRGBA(icol);
+ m_mesh->SetMeshModified(true);
+ return 0;
+ }
+ }
+
+ return SCA_IObject::_setattr(attr, pyvalue);
+}
+
+KX_VertexProxy::KX_VertexProxy(KX_MeshProxy*mesh, RAS_TexVert* vertex)
+: m_vertex(vertex),
+ m_mesh(mesh)
+{
+}
+
+KX_VertexProxy::~KX_VertexProxy()
+{
+}
+
+
+
+// stuff for cvalue related things
+CValue* KX_VertexProxy::Calc(VALUE_OPERATOR, CValue *) { return NULL;}
+CValue* KX_VertexProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { return NULL;}
+STR_String sVertexName="vertex";
+const STR_String & KX_VertexProxy::GetText() {return sVertexName;};
+float KX_VertexProxy::GetNumber() { return -1;}
+STR_String KX_VertexProxy::GetName() { return sVertexName;}
+void KX_VertexProxy::SetName(STR_String) { };
+CValue* KX_VertexProxy::GetReplica() { return NULL;}
+void KX_VertexProxy::ReplicaSetName(STR_String) {};
+
+
+// stuff for python integration
+
+PyObject* KX_VertexProxy::PyGetXYZ(PyObject*,
+ PyObject*,
+ PyObject*)
+{
+ return PyObjectFrom(MT_Point3(m_vertex->getLocalXYZ()));
+}
+
+PyObject* KX_VertexProxy::PySetXYZ(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ MT_Point3 vec;
+ if (PyVecArgTo(args, vec))
+ {
+ m_vertex->SetXYZ(vec);
+ m_mesh->SetMeshModified(true);
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+PyObject* KX_VertexProxy::PyGetNormal(PyObject*,
+ PyObject*,
+ PyObject*)
+{
+ return PyObjectFrom(MT_Vector3(m_vertex->getNormal()));
+}
+
+PyObject* KX_VertexProxy::PySetNormal(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ MT_Vector3 vec;
+ if (PyVecArgTo(args, vec))
+ {
+ m_vertex->SetNormal(vec);
+ m_mesh->SetMeshModified(true);
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+
+PyObject* KX_VertexProxy::PyGetRGBA(PyObject*,
+ PyObject*,
+ PyObject*)
+{
+ int *rgba = (int *) m_vertex->getRGBA();
+ return PyInt_FromLong(*rgba);
+}
+
+PyObject* KX_VertexProxy::PySetRGBA(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ float r, g, b, a;
+ if (PyArg_ParseTuple(args, "(ffff)", &r, &g, &b, &a))
+ {
+ m_vertex->SetRGBA(MT_Vector4(r, g, b, a));
+ m_mesh->SetMeshModified(true);
+ Py_Return;
+ }
+ PyErr_Clear();
+
+ int rgba;
+ if (PyArg_ParseTuple(args,"i",&rgba))
+ {
+ m_vertex->SetRGBA(rgba);
+ m_mesh->SetMeshModified(true);
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+
+PyObject* KX_VertexProxy::PyGetUV(PyObject*,
+ PyObject*,
+ PyObject*)
+{
+ return PyObjectFrom(MT_Vector2(m_vertex->getUV1()));
+}
+
+PyObject* KX_VertexProxy::PySetUV(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ MT_Point2 vec;
+ if (PyVecArgTo(args, vec))
+ {
+ m_vertex->SetUV(vec);
+ m_mesh->SetMeshModified(true);
+ Py_Return;
+ }
+
+ return NULL;
+}
+
+PyObject* KX_VertexProxy::PyGetUV2(PyObject*,
+ PyObject*,
+ PyObject*)
+{
+ return PyObjectFrom(MT_Vector2(m_vertex->getUV2()));
+}
+
+PyObject* KX_VertexProxy::PySetUV2(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ MT_Point2 vec;
+ unsigned int unit=0;
+ PyObject* list=0;
+ if(PyArg_ParseTuple(args, "Oi", &list, &unit))
+ {
+ if (PyVecTo(list, vec))
+ {
+ m_vertex->SetFlag((m_vertex->getFlag()|TV_2NDUV));
+ m_vertex->SetUnit(unit);
+ m_vertex->SetUV2(vec);
+ m_mesh->SetMeshModified(true);
+ Py_Return;
+ }
+ }
+ return NULL;
+}
diff --git a/source/gameengine/Ketsji/KX_VertexProxy.h b/source/gameengine/Ketsji/KX_VertexProxy.h
new file mode 100644
index 00000000000..acae9cf5a34
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_VertexProxy.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 __KX_VERTEXPROXY
+#define __KX_VERTEXPROXY
+
+#include "SCA_IObject.h"
+
+class KX_VertexProxy : public SCA_IObject
+{
+ Py_Header;
+protected:
+
+ class RAS_TexVert* m_vertex;
+ class KX_MeshProxy* m_mesh;
+public:
+ KX_VertexProxy(class KX_MeshProxy*mesh, class RAS_TexVert* vertex);
+ virtual ~KX_VertexProxy();
+
+ // stuff for cvalue related things
+ CValue* Calc(VALUE_OPERATOR op, CValue *val) ;
+ CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+ const STR_String & GetText();
+ float GetNumber();
+ STR_String GetName();
+ void SetName(STR_String name); // Set the name of the value
+ void ReplicaSetName(STR_String name);
+ CValue* GetReplica();
+
+
+// stuff for python integration
+ virtual PyObject* _getattr(const STR_String& attr);
+ virtual int _setattr(const STR_String& attr, PyObject *pyvalue);
+
+ KX_PYMETHOD(KX_VertexProxy,GetXYZ);
+ KX_PYMETHOD(KX_VertexProxy,SetXYZ);
+ KX_PYMETHOD(KX_VertexProxy,GetUV);
+ KX_PYMETHOD(KX_VertexProxy,SetUV);
+
+ KX_PYMETHOD(KX_VertexProxy,GetUV2);
+ KX_PYMETHOD(KX_VertexProxy,SetUV2);
+
+ KX_PYMETHOD(KX_VertexProxy,GetRGBA);
+ KX_PYMETHOD(KX_VertexProxy,SetRGBA);
+ KX_PYMETHOD(KX_VertexProxy,GetNormal);
+ KX_PYMETHOD(KX_VertexProxy,SetNormal);
+
+};
+
+#endif //__KX_VERTEXPROXY
+
diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp
new file mode 100644
index 00000000000..8ec3e05e303
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp
@@ -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): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Actuator to toggle visibility/invisibility of objects
+ */
+
+#include "KX_VisibilityActuator.h"
+#include "KX_GameObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_VisibilityActuator::KX_VisibilityActuator(
+ SCA_IObject* gameobj,
+ bool visible,
+ PyTypeObject* T
+ )
+ : SCA_IActuator(gameobj,T),
+ m_visible(visible)
+{
+ // intentionally empty
+}
+
+KX_VisibilityActuator::~KX_VisibilityActuator(
+ void
+ )
+{
+ // intentionally empty
+}
+
+CValue*
+KX_VisibilityActuator::GetReplica(
+ void
+ )
+{
+ KX_VisibilityActuator* replica = new KX_VisibilityActuator(*this);
+ replica->ProcessReplica();
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+}
+
+bool
+KX_VisibilityActuator::Update()
+{
+ bool bNegativeEvent = IsNegativeEvent();
+
+ RemoveAllEvents();
+ if (bNegativeEvent) return false;
+
+ KX_GameObject *obj = (KX_GameObject*) GetParent();
+
+ obj->SetVisible(m_visible);
+ obj->MarkVisible();
+
+ return true;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject
+KX_VisibilityActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_VisibilityActuator",
+ sizeof(KX_VisibilityActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject
+KX_VisibilityActuator::Parents[] = {
+ &KX_VisibilityActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef
+KX_VisibilityActuator::Methods[] = {
+ {"set", (PyCFunction) KX_VisibilityActuator::sPySetVisible,
+ METH_VARARGS, SetVisible_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject*
+KX_VisibilityActuator::_getattr(
+ const STR_String& attr
+ )
+{
+ _getattr_up(SCA_IActuator);
+};
+
+
+
+/* set visibility ---------------------------------------------------------- */
+char
+KX_VisibilityActuator::SetVisible_doc[] =
+"setVisible(visible?)\n"
+"\t - visible? : Make the object visible? (KX_TRUE, KX_FALSE)"
+"\tSet the properties of the actuator.\n";
+PyObject*
+
+KX_VisibilityActuator::PySetVisible(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int vis;
+
+ if(!PyArg_ParseTuple(args, "i", &vis)) {
+ return NULL;
+ }
+
+ m_visible = PyArgToBool(vis);
+
+ Py_Return;
+}
+
+
diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.h b/source/gameengine/Ketsji/KX_VisibilityActuator.h
new file mode 100644
index 00000000000..9a78eb1cc07
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_VisibilityActuator.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 *****
+ * Actuator to toggle visibility/invisibility of objects
+ */
+
+#ifndef __KX_VISIBILITYACTUATOR
+#define __KX_VISIBILITYACTUATOR
+
+#include "SCA_IActuator.h"
+
+class KX_VisibilityActuator : public SCA_IActuator
+{
+ Py_Header;
+
+ /** Make visible? */
+ bool m_visible;
+
+ public:
+
+ KX_VisibilityActuator(
+ SCA_IObject* gameobj,
+ bool visible,
+ PyTypeObject* T=&Type
+ );
+
+ virtual
+ ~KX_VisibilityActuator(
+ void
+ );
+
+ virtual CValue*
+ GetReplica(
+ void
+ );
+
+ virtual bool
+ Update();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+ //KX_PYMETHOD_DOC
+ KX_PYMETHOD_DOC(KX_VisibilityActuator,SetVisible);
+
+};
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_WorldInfo.cpp b/source/gameengine/Ketsji/KX_WorldInfo.cpp
new file mode 100644
index 00000000000..c2e696f856e
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_WorldInfo.cpp
@@ -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 *****
+ */
+
+#include "KX_WorldInfo.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_WorldInfo::~KX_WorldInfo()
+{
+}
+
diff --git a/source/gameengine/Ketsji/KX_WorldInfo.h b/source/gameengine/Ketsji/KX_WorldInfo.h
new file mode 100644
index 00000000000..ecc0c04a17b
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_WorldInfo.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef __KX_WORLDINFO_H
+#define __KX_WORLDINFO_H
+
+#include "MT_Scalar.h"
+
+class MT_CmMatrix4x4;
+
+class KX_WorldInfo
+{
+public:
+ KX_WorldInfo(){}
+ virtual ~KX_WorldInfo();
+
+ virtual bool hasWorld()=0;
+ virtual bool hasMist()=0;
+ virtual float getBackColorRed()=0;
+ virtual float getBackColorGreen()=0;
+ virtual float getBackColorBlue()=0;
+ virtual float getMistStart()=0;
+ virtual float getMistDistance()=0;
+ virtual float getMistColorRed()=0;
+ virtual float getMistColorGreen()=0;
+ virtual float getMistColorBlue()=0;
+
+ virtual float getAmbientColorRed()=0;
+ virtual float getAmbientColorGreen()=0;
+ virtual float getAmbientColorBlue()=0;
+
+ virtual void setMistStart(float)=0;
+ virtual void setMistDistance(float)=0;
+ virtual void setMistColorRed(float)=0;
+ virtual void setMistColorGreen(float)=0;
+ virtual void setMistColorBlue(float)=0;
+};
+
+#endif //__KX_WORLDINFO_H
+
diff --git a/source/gameengine/Ketsji/KX_WorldIpoController.cpp b/source/gameengine/Ketsji/KX_WorldIpoController.cpp
new file mode 100644
index 00000000000..ded251f391e
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_WorldIpoController.cpp
@@ -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 *****
+ */
+
+#include "KX_WorldIpoController.h"
+#include "KX_ScalarInterpolator.h"
+#include "KX_WorldInfo.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(_WIN64)
+typedef unsigned __int64 uint_ptr;
+#else
+typedef unsigned long uint_ptr;
+#endif
+
+bool KX_WorldIpoController::Update(double currentTime)
+{
+ if (m_modified)
+ {
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ (*i)->Execute(m_ipotime);//currentTime);
+ }
+
+ KX_WorldInfo *world = NULL;
+
+ if (m_modify_mist_start) {
+ world->setMistStart(m_mist_start);
+ }
+
+ if (m_modify_mist_color) {
+ world->setMistColorRed(m_mist_rgb[0]);
+ world->setMistColorGreen(m_mist_rgb[1]);
+ world->setMistColorBlue(m_mist_rgb[2]);
+ }
+
+ if (m_modify_mist_dist) {
+ world->setMistDistance(m_mist_dist);
+ }
+
+ m_modified=false;
+ }
+ return false;
+}
+
+
+void KX_WorldIpoController::AddInterpolator(KX_IInterpolator* interp)
+{
+ this->m_interpolators.push_back(interp);
+}
+
+
+SG_Controller* KX_WorldIpoController::GetReplica(class SG_Node* destnode)
+{
+ KX_WorldIpoController* iporeplica = new KX_WorldIpoController(*this);
+ // clear object that ipo acts on
+ iporeplica->ClearObject();
+
+ // dirty hack, ask Gino for a better solution in the ipo implementation
+ // hacken en zagen, in what we call datahiding, not written for replication :(
+
+ T_InterpolatorList oldlist = m_interpolators;
+ iporeplica->m_interpolators.clear();
+
+ T_InterpolatorList::iterator i;
+ for (i = oldlist.begin(); !(i == oldlist.end()); ++i) {
+ KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i));
+ iporeplica->AddInterpolator(copyipo);
+
+ MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget();
+ uint_ptr orgbase = (uint_ptr)this;
+ uint_ptr orgloc = (uint_ptr)scaal;
+ uint_ptr offset = orgloc-orgbase;
+ uint_ptr newaddrbase = (uint_ptr)iporeplica + offset;
+ MT_Scalar* blaptr = (MT_Scalar*) newaddrbase;
+ copyipo->SetNewTarget((MT_Scalar*)blaptr);
+ }
+
+ return iporeplica;
+}
+
+KX_WorldIpoController::~KX_WorldIpoController()
+{
+
+ T_InterpolatorList::iterator i;
+ for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ delete (*i);
+ }
+
+}
diff --git a/source/gameengine/Ketsji/KX_WorldIpoController.h b/source/gameengine/Ketsji/KX_WorldIpoController.h
new file mode 100644
index 00000000000..562a2769807
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_WorldIpoController.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.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 KX_WORLDIPOCONTROLLER_H
+#define KX_WORLDIPOCONTROLLER_H
+
+#include "SG_Controller.h"
+#include "SG_Spatial.h"
+#include "KX_IInterpolator.h"
+
+class KX_WorldIpoController : public SG_Controller
+{
+public:
+ MT_Scalar m_mist_rgb[3];
+ MT_Scalar m_mist_start;
+ MT_Scalar m_mist_dist;
+
+private:
+ T_InterpolatorList m_interpolators;
+ unsigned short m_modify_mist_color : 1;
+ unsigned short m_modify_mist_start : 1;
+ unsigned short m_modify_mist_dist : 1;
+ bool m_modified;
+
+ double m_ipotime;
+
+public:
+ KX_WorldIpoController() :
+ m_modify_mist_color(false),
+ m_modify_mist_start(false),
+ m_modify_mist_dist(false),
+ m_modified(true),
+ m_ipotime(0.0)
+ {}
+
+ virtual ~KX_WorldIpoController();
+
+ virtual SG_Controller* GetReplica(class SG_Node* destnode);
+
+ virtual bool Update(double time);
+
+ virtual void SetSimulatedTime(double time) {
+ m_ipotime = time;
+ m_modified = true;
+ }
+
+ void SetModifyMistStart(bool modify) {
+ m_modify_mist_start = modify;
+ }
+
+ void SetModifyMistColor(bool modify) {
+ m_modify_mist_color = modify;
+ }
+
+ void SetModifyMistDist(bool modify) {
+ m_modify_mist_dist = modify;
+ }
+
+ void
+ SetOption(
+ int option,
+ int value
+ ){
+ // intentionally empty
+ };
+
+ void AddInterpolator(KX_IInterpolator* interp);
+};
+
+#endif // KX_LIGHTIPOSGCONTROLLER_H
+
diff --git a/source/gameengine/Ketsji/Makefile b/source/gameengine/Ketsji/Makefile
new file mode 100644
index 00000000000..f7813c80a59
--- /dev/null
+++ b/source/gameengine/Ketsji/Makefile
@@ -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 *****
+#
+#
+
+LIBNAME = ketsji
+DIR = $(OCGDIR)/gameengine/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += $(OGL_CPPFLAGS)
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) -I../../blender/python
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include
+CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO) -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_SOLID)/include
+CPPFLAGS += -I$(NAN_BULLET2)/include
+CPPFLAGS += -I../Rasterizer/RAS_OpenGLRasterizer
+CPPFLAGS += -I../Rasterizer -I../GameLogic -I../SceneGraph
+CPPFLAGS += -I../BlenderRoutines -I../Expressions
+CPPFLAGS += -I../../kernel/gen_system
+CPPFLAGS += -I../Network -IKXNetwork
+CPPFLAGS += -I../Physics/common
+CPPFLAGS += -I../Physics/Dummy
+CPPFLAGS += -I../Physics/Sumo
+CPPFLAGS += -I../Physics/BlOde
+CPPFLAGS += -I../Physics/Bullet
+CPPFLAGS += -I.
+CPPFLAGS += -I../Converter
+CPPFLAGS += -I../../blender/blenkernel
+CPPFLAGS += -I../../blender/blenlib
+CPPFLAGS += -I../../blender/include
+CPPFLAGS += -I../../blender/makesdna
+CPPFLAGS += -I../../blender/imbuf
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+
+###########################
+
+SOURCEDIR = source/gameengine/Ketsji
+DIRS = KXNetwork
+
+include nan_subdirs.mk
+
diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript
new file mode 100644
index 00000000000..cb213522f1d
--- /dev/null
+++ b/source/gameengine/Ketsji/SConscript
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+import sys
+
+Import ('env')
+
+sources = env.Glob('*.cpp')
+
+incs = '. #source/kernel/gen_system #intern/string #intern/guardedalloc'
+incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #intern/bmfont'
+incs += ' #intern/SoundSystem #intern/SoundSystem/include #intern/SoundSystem/openal'
+incs += ' #intern/SoundSystem/dummy #intern/SoundSystem/intern #source/gameengine/Converter'
+incs += ' #source/gameengine/BlenderRoutines #source/blender/imbuf #intern/moto/include'
+incs += ' #source/gameengine/Ketsji #source/gameengine/Ketsji/KXNetwork #source/blender/blenlib'
+incs += ' #source/blender/blenkernel #source/blender #source/blender/include'
+incs += ' #source/blender/makesdna #source/blender/python #source/gameengine/Rasterizer'
+incs += ' #source/gameengine/GameLogic #source/gameengine/Expressions #source/gameengine/Network'
+incs += ' #source/gameengine/SceneGraph #source/gameengine/Physics/common #source/gameengine/Physics/Bullet'
+incs += ' #source/gameengine/Physics/BlOde #source/gameengine/Physics/Dummy'
+incs += ' #source/gameengine/Physics/Sumo #source/gameengine/Physics/Sumo/include'
+incs += ' #source/gameengine/Physics/Sumo/Fuzzics/include #source/gameengine/Network/LoopBackNetwork'
+incs += ' #source/blender/misc #source/blender/blenloader'
+
+cflags = []
+if env['OURPLATFORM'] == 'win32-vc':
+ cflags.append('/GR')
+ cflags.append('/Ox')
+
+incs += ' ' + env['BF_SOLID_INC']
+incs += ' ' + env['BF_PYTHON_INC']
+incs += ' ' + env['BF_SDL_INC']
+incs += ' ' + env['BF_BULLET_INC']
+incs += ' ' + env['BF_OPENGL_INC']
+
+env.BlenderLib ( 'bf_ketsji', sources, Split(incs), [], libtype=['game','player'], priority=[25, 72], compileflags = cflags )
diff --git a/source/gameengine/Makefile b/source/gameengine/Makefile
new file mode 100644
index 00000000000..00503e9f8b4
--- /dev/null
+++ b/source/gameengine/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 *****
+#
+# Bounces make to subdirectories.
+
+include nan_definitions.mk
+
+SOURCEDIR = source/gameengine
+DIR = $(OCGDIR)/gameengine
+DIRS = BlenderRoutines
+DIRS += Converter
+DIRS += Expressions GameLogic Ketsji Rasterizer SceneGraph
+DIRS += Network Physics
+
+ifeq ($(WITH_BF_BLENDERGAMEENGINE),true)
+ DIRS += GamePlayer
+endif
+
+include nan_subdirs.mk
diff --git a/source/gameengine/Network/CMakeLists.txt b/source/gameengine/Network/CMakeLists.txt
new file mode 100644
index 00000000000..df002ca00b7
--- /dev/null
+++ b/source/gameengine/Network/CMakeLists.txt
@@ -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) 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 *.cpp)
+
+SET(INC
+ .
+ ../../../source/kernel/gen_system
+ ../../../intern/string
+ ../../../intern/moto/include
+)
+
+BLENDERLIB(bf_ngnetwork "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_ngnetwork', sources, Split(incs), [], libtype=['game2', 'player'], priority=[15, 160] )
diff --git a/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt b/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt
new file mode 100644
index 00000000000..2ced70eab5a
--- /dev/null
+++ b/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt
@@ -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) 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 NG_LoopBackNetworkDeviceInterface.cpp)
+
+SET(INC
+ .
+ ../../../../source/kernel/gen_system
+ ../../../../intern/string
+ ../../../../source/gameengine/Network
+)
+
+BLENDERLIB(bf_loopbacknetwork "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_loopbacknetwork', Split(sources), Split(incs), defines=[],libtype=['game2', 'player'], priority=[25, 165] )
diff --git a/source/gameengine/Network/LoopBackNetwork/Makefile b/source/gameengine/Network/LoopBackNetwork/Makefile
new file mode 100644
index 00000000000..19fe362b8f7
--- /dev/null
+++ b/source/gameengine/Network/LoopBackNetwork/Makefile
@@ -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 *****
+#
+#
+
+LIBNAME = LoopBackNetwork
+DIR = $(OCGDIR)/gameengine/Network/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I..
+CPPFLAGS += -I../../../kernel/gen_system
+
diff --git a/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.cpp b/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.cpp
new file mode 100644
index 00000000000..e36aa4750af
--- /dev/null
+++ b/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.cpp
@@ -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 *****
+ * LoopbackNetworkDeviceInterface derived from NG_NetworkDeviceInterface
+ */
+
+#include "NG_LoopBackNetworkDeviceInterface.h"
+#include "NG_NetworkMessage.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// temporary debugging printf's
+#ifdef NAN_NET_DEBUG
+ #include <stdio.h>
+#endif
+
+NG_LoopBackNetworkDeviceInterface::NG_LoopBackNetworkDeviceInterface()
+{
+ m_currentQueue=0;
+ Online(); // LoopBackdevices are 'online' immediately
+}
+
+NG_LoopBackNetworkDeviceInterface::~NG_LoopBackNetworkDeviceInterface()
+{
+}
+
+// perhaps this should go to the shared/common implementation too
+void NG_LoopBackNetworkDeviceInterface::NextFrame()
+{
+ // Release reference to the messages while emptying the queue
+ while (m_messages[m_currentQueue].size() > 0) {
+#ifdef NAN_NET_DEBUG
+ printf("NG_LBNDI::NextFrame %d '%s'\n", m_currentQueue, m_messages[m_currentQueue][0]->GetSubject().ReadPtr());
+#endif
+ // Should do assert(m_events[0]);
+ m_messages[m_currentQueue][0]->Release();
+ m_messages[m_currentQueue].pop_front();
+ }
+ //m_messages[m_currentQueue].clear();
+
+ m_currentQueue=1-m_currentQueue;
+}
+
+STR_String NG_LoopBackNetworkDeviceInterface::GetNetworkVersion()
+{
+ return LOOPBACK_NETWORK_VERSION;
+}
+
+void NG_LoopBackNetworkDeviceInterface::SendNetworkMessage(NG_NetworkMessage* nwmsg)
+{
+#ifdef NAN_NET_DEBUG
+ printf("NG_LBNDI::SendNetworkMessage %d, '%s'->'%s' '%s' '%s'\n",
+ 1-m_currentQueue,
+ nwmsg->GetDestinationName().ReadPtr(),
+ nwmsg->GetSenderName().ReadPtr(),
+ nwmsg->GetSubject().ReadPtr(),
+ nwmsg->GetMessageText().ReadPtr());
+#endif
+ int backqueue = 1-m_currentQueue;
+
+ nwmsg->AddRef();
+ m_messages[backqueue].push_back(nwmsg);
+}
+
+vector<NG_NetworkMessage*> NG_LoopBackNetworkDeviceInterface::RetrieveNetworkMessages()
+{
+ vector<NG_NetworkMessage*> messages;
+
+ std::deque<NG_NetworkMessage*>::iterator mesit=m_messages[m_currentQueue].begin();
+ for (; !(mesit == m_messages[m_currentQueue].end()); ++mesit)
+ {
+
+ // We don't increase the reference count for these messages. We
+ // are passing a vector of messages in the interface and not
+ // explicitily storing the messgaes for long term usage
+
+ messages.push_back(*mesit);
+
+#ifdef NAN_NET_DEBUG
+ printf("NG_LBNDI::RetrieveNetworkMessages %d '%s'->'%s' '%s' '%s'\n",
+ m_currentQueue,
+ (*mesit)->GetDestinationName().ReadPtr(),
+ (*mesit)->GetSenderName().ReadPtr(),
+ (*mesit)->GetSubject().ReadPtr(),
+ (*mesit)->GetMessageText().ReadPtr());
+#endif
+ }
+ return messages;
+}
+
diff --git a/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.h b/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.h
new file mode 100644
index 00000000000..bedf27b292b
--- /dev/null
+++ b/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.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 *****
+ * LoopbackNetworkDeviceInterface derived from NG_NetworkDeviceInterface
+ */
+#ifndef NG_LOOPBACKNETWORKDEVICEINTERFACE_H
+#define NG_LOOPBACKNETWORKDEVICEINTERFACE_H
+
+#include <deque>
+#include "NG_NetworkDeviceInterface.h"
+
+class NG_LoopBackNetworkDeviceInterface : public NG_NetworkDeviceInterface
+{
+ enum {
+ LOOPBACK_NETWORK_VERSION=28022001
+ };
+
+ std::deque<NG_NetworkMessage*> m_messages[2];
+ int m_currentQueue;
+
+public:
+ NG_LoopBackNetworkDeviceInterface();
+ virtual ~NG_LoopBackNetworkDeviceInterface();
+
+ /**
+ * Clear message buffer
+ */
+ virtual void NextFrame();
+
+ bool Connect(char *address, unsigned int port, char *password,
+ unsigned int localport, unsigned int timeout) {
+ return true;}
+ bool Disconnect(void) {return true;}
+
+ virtual void SendNetworkMessage(class NG_NetworkMessage* msg);
+ virtual vector<NG_NetworkMessage*> RetrieveNetworkMessages();
+
+ STR_String GetNetworkVersion();
+};
+
+#endif //NG_LOOPBACKNETWORKDEVICEINTERFACE_H
+
diff --git a/source/gameengine/Network/LoopBackNetwork/SConscript b/source/gameengine/Network/LoopBackNetwork/SConscript
new file mode 100644
index 00000000000..987603f1a49
--- /dev/null
+++ b/source/gameengine/Network/LoopBackNetwork/SConscript
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = 'NG_LoopBackNetworkDeviceInterface.cpp'
+
+incs = '. #source/kernel/gen_system #intern/string #source/gameengine/Network'
+
+env.BlenderLib ( 'bf_loopbacknetwork', Split(sources), Split(incs), defines=[],libtype=['game2', 'player'], priority=[25, 165] )
diff --git a/source/gameengine/Network/Makefile b/source/gameengine/Network/Makefile
new file mode 100644
index 00000000000..dd4819f46e5
--- /dev/null
+++ b/source/gameengine/Network/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 = Network
+DIR = $(OCGDIR)/gameengine/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I../GameLogic
+CPPFLAGS += -I../../kernel/gen_system
+
+##############
+
+DIRS = LoopBackNetwork
+SOURCEDIR = source/gameengine/Network
+
+include nan_subdirs.mk
diff --git a/source/gameengine/Network/NG_NetworkDeviceInterface.h b/source/gameengine/Network/NG_NetworkDeviceInterface.h
new file mode 100644
index 00000000000..7975fee540c
--- /dev/null
+++ b/source/gameengine/Network/NG_NetworkDeviceInterface.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 *****
+ * NetworkGameengine_NetworkDeviceInterface
+ * Functions like (de)initialize network, get library version
+ * To be derived by loopback and network libraries
+ */
+#ifndef NG_NETWORKDEVICEINTERFACE_H
+#define NG_NETWORKDEVICEINTERFACE_H
+
+#include "NG_NetworkMessage.h"
+#include <vector>
+
+class NG_NetworkDeviceInterface
+{
+private:
+ // candidates for shared/common implementation class
+ bool m_online;
+public:
+ NG_NetworkDeviceInterface() {};
+ virtual ~NG_NetworkDeviceInterface() {};
+
+ virtual void NextFrame()=0;
+
+ /**
+ * Mark network connection online
+ */
+ void Online(void) { m_online = true; }
+ /**
+ * Mark network connection offline
+ */
+ void Offline(void) { m_online = false; }
+ /**
+ * Is the network connection established ?
+ */
+ bool IsOnline(void) { return m_online; }
+
+ virtual bool Connect(char *address, unsigned int port, char *password,
+ unsigned int localport, unsigned int timeout)=0;
+ virtual bool Disconnect(void)=0;
+
+ virtual void SendNetworkMessage(NG_NetworkMessage* msg)=0;
+ /**
+ * read NG_NetworkMessage from library buffer, may be
+ * irrelevant for loopbackdevices
+ */
+
+ virtual std::vector<NG_NetworkMessage*> RetrieveNetworkMessages()=0;
+
+ /**
+ * number of messages in device hash for this frame
+ */
+
+ virtual STR_String GetNetworkVersion(void)=0;
+};
+
+#endif //NG_NETWORKDEVICEINTERFACE_H
+
diff --git a/source/gameengine/Network/NG_NetworkMessage.cpp b/source/gameengine/Network/NG_NetworkMessage.cpp
new file mode 100644
index 00000000000..44f13ae40c4
--- /dev/null
+++ b/source/gameengine/Network/NG_NetworkMessage.cpp
@@ -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 *****
+ * generic Network Message implementation
+ */
+#include "NG_NetworkMessage.h"
+#include <assert.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int NG_NetworkMessage::s_nextID = 3; // just some number to start with
+
+NG_NetworkMessage::NG_NetworkMessage(
+ const STR_String& to,
+ const STR_String& from,
+ const STR_String& subject,
+ const STR_String& body) :
+ m_uniqueMessageID(s_nextID++),
+ m_refcount(1),
+ m_to(to),
+ m_from(from),
+ m_subject(subject),
+ m_message(body)
+{
+}
+
+NG_NetworkMessage::~NG_NetworkMessage()
+{
+ assert(m_refcount==0);
+}
diff --git a/source/gameengine/Network/NG_NetworkMessage.h b/source/gameengine/Network/NG_NetworkMessage.h
new file mode 100644
index 00000000000..b3efea402b2
--- /dev/null
+++ b/source/gameengine/Network/NG_NetworkMessage.h
@@ -0,0 +1,131 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * NetworkGame_NetworkMessage generic Network Message class
+ */
+#ifndef NG_NETWORKMESSAGE_H
+#define NG_NETWORKMESSAGE_H
+
+#include "STR_HashedString.h"
+
+class NG_NetworkMessage
+{
+ static int s_nextID;
+ int m_uniqueMessageID; // intern counting MessageID
+ unsigned int m_ClientId;
+ int m_refcount;
+
+ STR_String m_to; // receiver
+ STR_String m_from; // sender
+ STR_String m_subject; // empty or propName
+ STR_String m_message; // message or propValue
+
+protected:
+ ~NG_NetworkMessage();
+
+public:
+ NG_NetworkMessage(
+ const STR_String& to,
+ const STR_String& from,
+ const STR_String& subject,
+ const STR_String& body);
+
+ void AddRef() {
+ m_refcount++;
+ }
+
+ // This is not nice code you should'nt need to resort to
+ // delete this.
+ void Release()
+ {
+ if (! --m_refcount)
+ {
+ delete this;
+ }
+ }
+
+ /**
+ * set the content of this message
+ */
+ void SetMessageText(const STR_String& msgtext) {
+ m_message = msgtext;
+ }
+
+ /**
+ * get the (read-only) To part of this message
+ */
+ const STR_String& GetDestinationName() { return m_to;};
+
+ /**
+ * get the (read-only) From part of this message
+ */
+ const STR_String& GetSenderName() { return m_from;};
+
+ /**
+ * get the (read-only) Subject part of this message
+ */
+ const STR_String& GetSubject() { return m_subject;};
+
+ /**
+ * get the (read-only) Body part of this message
+ */
+ const STR_String& GetMessageText() {
+//cout << "GetMessageText " << m_message << "\n";
+ return m_message;
+ }
+ const STR_String& GetMessageText() const {
+//cout << "GetMessageText " << m_message << "\n";
+ return m_message;
+ }
+
+ /**
+ * Set the NetworkMessage sender identifier
+ */
+ void SetSender(unsigned int ClientId) {
+ m_ClientId = ClientId;
+ }
+
+ /**
+ * Get the NetworkMessage sender identifier
+ */
+ unsigned int GetSender(void) {
+ return m_ClientId;
+ }
+
+ /**
+ * get the unique Network Message ID
+ */
+ int GetMessageID() {
+ return m_uniqueMessageID;
+ }
+};
+
+#endif //NG_NETWORKMESSAGE_H
+
diff --git a/source/gameengine/Network/NG_NetworkObject.cpp b/source/gameengine/Network/NG_NetworkObject.cpp
new file mode 100644
index 00000000000..02805a9f91a
--- /dev/null
+++ b/source/gameengine/Network/NG_NetworkObject.cpp
@@ -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 *****
+ * NetworkGame_NetworkObject generic Network Object implementation
+ */
+#include "NG_NetworkObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+NG_NetworkObject::NG_NetworkObject()
+{
+}
+
+NG_NetworkObject::~NG_NetworkObject()
+{
+}
+
+const STR_String& NG_NetworkObject::GetName()
+{
+ return m_name;
+}
diff --git a/source/gameengine/Network/NG_NetworkObject.h b/source/gameengine/Network/NG_NetworkObject.h
new file mode 100644
index 00000000000..b5499010512
--- /dev/null
+++ b/source/gameengine/Network/NG_NetworkObject.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 *****
+ * NetworkGame_NetworkObject generic Network Object class
+ */
+#ifndef NG_NETWORKOBJECT_H
+#define NG_NETWORKOBJECT_H
+
+#include "STR_String.h"
+
+class NG_NetworkObject
+{
+ STR_String m_name;
+public:
+ NG_NetworkObject();
+ ~NG_NetworkObject();
+ const STR_String& GetName();
+};
+
+#endif //NG_NETWORKOBJECT_H
+
diff --git a/source/gameengine/Network/NG_NetworkScene.cpp b/source/gameengine/Network/NG_NetworkScene.cpp
new file mode 100644
index 00000000000..c66eb3730ac
--- /dev/null
+++ b/source/gameengine/Network/NG_NetworkScene.cpp
@@ -0,0 +1,275 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * NetworkSceneManagement generic implementation
+ */
+#include <stdio.h>
+#include <MT_assert.h>
+#include <algorithm>
+
+#include "NG_NetworkScene.h"
+#include "NG_NetworkDeviceInterface.h"
+#include "NG_NetworkMessage.h"
+#include "NG_NetworkObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+NG_NetworkScene::NG_NetworkScene(NG_NetworkDeviceInterface* nic)
+{
+ m_networkdevice = nic;
+}
+
+NG_NetworkScene::~NG_NetworkScene()
+{
+ ClearAllMessageMaps();
+}
+
+/**
+ * progress one frame, handle all network traffic
+ */
+void NG_NetworkScene::proceed(double curtime)
+{
+ if (!m_networkdevice) return;
+ if (!m_networkdevice->IsOnline()) return;
+
+ ClearAllMessageMaps();
+
+ // read all NetworkMessages from the device
+ vector<NG_NetworkMessage*> messages =
+ m_networkdevice->RetrieveNetworkMessages();
+
+ vector<NG_NetworkMessage*>::iterator mesit = messages.begin();
+ for (; !(mesit == messages.end()); mesit++) {
+ NG_NetworkMessage* message = (*mesit);
+ vector<NG_NetworkMessage*>* tmplist=NULL;
+
+ vector<NG_NetworkMessage*>** tmplistptr =
+ m_messagesByDestinationName[message->GetDestinationName()];
+ // if there is already a vector of messages, append, else create
+ // a new vector and insert into map
+ if (!tmplistptr) {
+ tmplist = new vector<NG_NetworkMessage*>;
+ m_messagesByDestinationName.insert(message->GetDestinationName(),
+ tmplist);
+ } else {
+ tmplist = *tmplistptr;
+ }
+ message->AddRef();
+ tmplist->push_back(message);
+ tmplist = NULL;
+
+ tmplistptr = m_messagesBySenderName[message->GetSenderName()];
+ // if there is already a vector of messages, append, else create
+ // a new vector and insert into map
+ if (!tmplistptr) {
+ tmplist = new vector<NG_NetworkMessage*>;
+ m_messagesBySenderName.insert(message->GetSenderName(), tmplist);
+ } else {
+ tmplist = *tmplistptr;
+ }
+ message->AddRef();
+ tmplist->push_back(message);
+ tmplist = NULL;
+
+ tmplistptr = m_messagesBySubject[message->GetSubject()];
+ // if there is already a vector of messages, append, else create
+ // a new vector and insert into map
+ if (!tmplistptr) {
+ tmplist = new vector<NG_NetworkMessage*>;
+ m_messagesBySubject.insert(message->GetSubject(), tmplist);
+ } else {
+ tmplist = *tmplistptr;
+ }
+ message->AddRef();
+ tmplist->push_back(message);
+ tmplist = NULL;
+ }
+}
+
+/**
+ * add a network object to the network scene
+ */
+void NG_NetworkScene::AddObject(NG_NetworkObject* object)
+{
+ if (! m_networkdevice->IsOnline()) return;
+
+ STR_String name = object->GetName();
+ m_networkObjects.insert(name, object);
+}
+
+/**
+ * remove a network object from the network scene
+ */
+void NG_NetworkScene::RemoveObject(NG_NetworkObject* object)
+{
+ if (! m_networkdevice->IsOnline()) return;
+
+ STR_String name = object->GetName();
+ m_networkObjects.remove(name);
+}
+
+/**
+ * remove all network scene objects at once
+ */
+void NG_NetworkScene::RemoveAllObjects()
+{
+ m_networkObjects.clear();
+}
+
+/**
+ * get a single network object given its name
+ */
+NG_NetworkObject* NG_NetworkScene::FindNetworkObject(const STR_String& objname) {
+ NG_NetworkObject *nwobj = NULL;
+ if (! m_networkdevice->IsOnline()) return nwobj;
+
+ NG_NetworkObject **nwobjptr = m_networkObjects[objname];
+ if (nwobjptr) {
+ nwobj = *nwobjptr;
+ }
+
+ return nwobj;
+}
+
+bool NG_NetworkScene::ConstraintsAreValid(
+ const STR_String& from,
+ const STR_String& subject,
+ NG_NetworkMessage* message)
+{
+ vector<NG_NetworkMessage*>** fromlistptr = m_messagesBySenderName[from];
+ vector<NG_NetworkMessage*>** subjectlistptr = m_messagesBySubject[subject];
+
+ vector<NG_NetworkMessage*>* fromlist = (fromlistptr ? *fromlistptr : NULL);
+ vector<NG_NetworkMessage*>* subjectlist = (subjectlistptr ? *subjectlistptr : NULL);
+
+ return (
+ ( from.IsEmpty() || (!fromlist ? false : (!(std::find(fromlist->begin(), fromlist->end(), message) == fromlist->end())))
+ ) &&
+ ( subject.IsEmpty() || (!subjectlist ? false : (!(std::find(subjectlist->begin(), subjectlist->end(), message) == subjectlist->end())))
+ ));
+}
+
+vector<NG_NetworkMessage*> NG_NetworkScene::FindMessages(
+ const STR_String& to,
+ const STR_String& from,
+ const STR_String& subject,
+ bool spamallowed)
+{
+ vector<NG_NetworkMessage*> foundmessages;
+ bool notfound = false;
+
+ // broad phase
+ notfound = ((to.IsEmpty() || spamallowed) ? notfound : m_messagesByDestinationName[to] == NULL);
+ if (!notfound)
+ notfound = (from.IsEmpty() ? notfound : m_messagesBySenderName[from] == NULL);
+ if (!notfound)
+ notfound = (subject.IsEmpty() ? notfound : m_messagesBySubject[subject] == NULL);
+ if (notfound) {
+ // it's definately NOT in the scene, so stop looking
+ } else { // narrow phase
+ // possibly it's there, but maybe not (false hit)
+ if (to.IsEmpty()) {
+ // take all messages, and check other fields
+ MT_assert(!"objectnames that are empty are not valid, so make it a hobby project :)\n");
+ } else {
+ //todo: find intersection of messages (that are in other 2 maps)
+ vector<NG_NetworkMessage*>** tolistptr = m_messagesByDestinationName[to];
+ if (tolistptr) {
+ vector<NG_NetworkMessage*>* tolist = *tolistptr;
+ vector<NG_NetworkMessage*>::iterator listit;
+ for (listit=tolist->begin();!(listit==tolist->end());listit++) {
+ NG_NetworkMessage* message = *listit;
+ if (ConstraintsAreValid(from, subject, message)) {
+ message->AddRef();
+ foundmessages.push_back(message);
+ }
+ }
+ }
+ // TODO find intersection of messages (that are in other 2 maps)
+ if (spamallowed) {
+ tolistptr = m_messagesByDestinationName[""];
+ if (tolistptr) {
+ vector<NG_NetworkMessage*>* tolist = *tolistptr;
+ vector<NG_NetworkMessage*>::iterator listit;
+ for (listit=tolist->begin();!(listit==tolist->end());listit++) {
+ NG_NetworkMessage* message = *listit;
+ if (ConstraintsAreValid(from, subject, message)) {
+ message->AddRef();
+ foundmessages.push_back(message);
+ }
+ }
+ }
+ }
+ }
+ }
+ return foundmessages;
+}
+
+void NG_NetworkScene::SendMessage(
+ const STR_String& to,
+ const STR_String& from,
+ const STR_String& subject,
+ const STR_String& message)
+{
+ NG_NetworkMessage* msg = new NG_NetworkMessage(to, from, subject, message);
+ m_networkdevice->SendNetworkMessage(msg);
+ msg->Release();
+}
+
+void NG_NetworkScene::ClearAllMessageMaps(void)
+{
+ ClearMessageMap(m_messagesByDestinationName);
+ ClearMessageMap(m_messagesBySenderName);
+ ClearMessageMap(m_messagesBySubject);
+}
+
+void NG_NetworkScene::ClearMessageMap(TMessageMap& map)
+{
+ // Release the messages in the map
+ for (int i = 0; i < map.size(); i++) {
+ vector<NG_NetworkMessage*>* msglist;
+ msglist = *(map.at(i));
+
+ // Iterate through the current vector and release all it's messages
+ vector<NG_NetworkMessage*>::iterator msgit;
+ for (msgit = msglist->begin(); msgit != msglist->end(); msgit++) {
+ (*msgit)->Release();
+ }
+
+ // Delete the actual vector
+ delete (msglist);
+ }
+
+ // Empty the map
+ map.clear();
+}
+
diff --git a/source/gameengine/Network/NG_NetworkScene.h b/source/gameengine/Network/NG_NetworkScene.h
new file mode 100644
index 00000000000..da3855d08bb
--- /dev/null
+++ b/source/gameengine/Network/NG_NetworkScene.h
@@ -0,0 +1,104 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * NetworkSceneManagement generic class
+ */
+#ifndef __NG_NETWORKSCENE_H
+#define __NG_NETWORKSCENE_H
+
+#include "GEN_Map.h"
+#include "STR_HashedString.h"
+#include <vector>
+
+class NG_NetworkDeviceInterface;
+
+class NG_NetworkScene
+{
+ class NG_NetworkDeviceInterface *m_networkdevice;
+ GEN_Map<STR_HashedString, class NG_NetworkObject *> m_networkObjects;
+
+ // GEN_Maps used as a 'Bloom' filter
+ typedef GEN_Map<STR_HashedString, std::vector<class NG_NetworkMessage*>* > TMessageMap;
+ TMessageMap m_messagesByDestinationName;
+ TMessageMap m_messagesBySenderName;
+ TMessageMap m_messagesBySubject;
+
+public:
+ NG_NetworkScene(NG_NetworkDeviceInterface *nic);
+ ~NG_NetworkScene();
+
+ /**
+ * progress one frame, handle all network traffic
+ */
+ void proceed(double curtime);
+
+ /**
+ * add a networkobject to the scene
+ */
+ void AddObject(NG_NetworkObject* object);
+
+ /**
+ * remove a networkobject to the scene
+ */
+ void RemoveObject(NG_NetworkObject* object);
+
+ /**
+ * remove all objects at once
+ */
+ void RemoveAllObjects();
+
+ /**
+ * send a message (ascii text) over the network
+ */
+ void SendMessage(const STR_String& to,const STR_String& from,const STR_String& subject,const STR_String& message);
+
+ /**
+ * find an object by name
+ */
+ NG_NetworkObject* FindNetworkObject(const STR_String& objname);
+
+ bool ConstraintsAreValid(const STR_String& from,const STR_String& subject,class NG_NetworkMessage* message);
+ vector<NG_NetworkMessage*> FindMessages(const STR_String& to,const STR_String& from,const STR_String& subject,bool spamallowed);
+
+protected:
+ /**
+ * Releases messages in message map members.
+ */
+ void ClearAllMessageMaps(void);
+
+ /**
+ * Releases messages for the given message map.
+ * @param map Message map with messages.
+ */
+ void ClearMessageMap(TMessageMap& map);
+};
+
+#endif //__NG_NETWORKSCENE_H
+
diff --git a/source/gameengine/Network/SConscript b/source/gameengine/Network/SConscript
new file mode 100644
index 00000000000..0778418045f
--- /dev/null
+++ b/source/gameengine/Network/SConscript
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('*.cpp') #'NG_NetworkMessage.cpp NG_NetworkObject.cpp NG_NetworkScene.cpp'
+
+incs = '. #source/kernel/gen_system #intern/string #intern/moto/include'
+
+env.BlenderLib ( 'bf_ngnetwork', sources, Split(incs), [], libtype=['game2', 'player'], priority=[15, 160] )
diff --git a/source/gameengine/Network/TerraplayNetwork/Makefile b/source/gameengine/Network/TerraplayNetwork/Makefile
new file mode 100644
index 00000000000..6fad0e0ca43
--- /dev/null
+++ b/source/gameengine/Network/TerraplayNetwork/Makefile
@@ -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 *****
+#
+#
+
+LIBNAME = TerraPlayNetwork
+DIR = $(OCGDIR)/gameengine/Network/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(LCGDIR)/terraplay/include
+CPPFLAGS += -I../../../kernel/gen_system
+CPPFLAGS += -I..
+
diff --git a/source/gameengine/Network/TerraplayNetwork/NG_TerraplayNetworkDeviceInterface.cpp b/source/gameengine/Network/TerraplayNetwork/NG_TerraplayNetworkDeviceInterface.cpp
new file mode 100644
index 00000000000..44a7e571b03
--- /dev/null
+++ b/source/gameengine/Network/TerraplayNetwork/NG_TerraplayNetworkDeviceInterface.cpp
@@ -0,0 +1,196 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * TerraplayNetworkDeviceInterface derived from NG_NetworkDeviceInterface
+ */
+
+#include "NG_TerraplayNetworkDeviceInterface.h"
+#include "NG_NetworkMessage.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//---- relocate these
+void NG_TerraplayNetworkDeviceInterface::interface_error(char *str, GASResult error) {
+ GASRString err_str = GAS->ErrorTranslate(error);
+ if (err_str.result == GASOK)
+ printf("%s: %s\n",str,err_str.ptr);
+ else
+ printf("%s: UNKNOWN (Error code %d)", error);
+}
+//---- END relocate these
+
+NG_TerraplayNetworkDeviceInterface::NG_TerraplayNetworkDeviceInterface()
+{
+ group_id = GASCLIENTIDNULL;
+ group_id_request_valid = false;
+ this->Offline();
+
+ if ((GAS = new GASInterface()) == NULL) {
+ // terror
+ printf("ERROR GAS Common Network Interface NOT created\n");
+ // do something useful
+ } else {
+ printf("GAS Common Network Interface created\n");
+ }
+}
+
+NG_TerraplayNetworkDeviceInterface::~NG_TerraplayNetworkDeviceInterface()
+{
+ if (GAS != NULL) {
+ delete GAS;
+ printf("GAS Common Network Interface deleted\n");
+ }
+}
+
+bool NG_TerraplayNetworkDeviceInterface::Connect(char *GAS_address,
+ unsigned int GAS_port, char *GAS_password, unsigned int localport,
+ unsigned int timeout)
+{
+ GASResult result;
+ printf("Establishing connection to GAS...\n");
+ result = GAS->ConnectionRequest(GAS_address, GAS_port,
+ GAS_password,localport, timeout);
+ if (result == GASOK) {
+ this->Online();
+ GASRClientId client_id = GAS->Connected();
+ if (client_id.result != GASOK) {
+ printf("... connected, but no client ID\n");
+ return false;
+ } else {
+ printf("Connected with client ID %d\n",
+ client_id.clientid);
+ return true;
+ }
+ } else {
+ interface_error("Connection", result);
+ return false;
+ }
+}
+
+bool NG_TerraplayNetworkDeviceInterface::Disconnect(void)
+{
+ int i = 0;
+ printf("Disconnecting...\n");
+ if (! this->IsOnline()) {
+ printf("ehh... /me was not connected\n");
+ return false;
+ }
+
+ GASRRequestId req = GAS->ConnectionClose();
+ if (req.result != GASWAITING) {
+ interface_error("ConnectionClose",req.result);
+ this->~NG_TerraplayNetworkDeviceInterface();
+ }
+ this->Offline();
+// dit is erg fout :( ik wil helemaal geen ~NG_ hier
+
+ while (true) {
+ GASRMessage gas_message;
+ GASResult result = GAS->GasActivity(GASBLOCK, 100);
+ if (++i>5000) {
+ printf("\nGiving up on waiting for connection close\n");
+ this->~NG_TerraplayNetworkDeviceInterface();
+ }
+ switch (result) {
+ case GASCONNECTIONOK:
+ break;
+ case GASGASMESSAGE:
+ gas_message = GAS->GasMessageGetNext();
+ if (gas_message.type == GASRCONNECTIONCLOSE) {
+ if (gas_message.result == GASOK ||
+ gas_message.result == GASALREADYDONE) {
+ return true;
+ } else {
+ interface_error("GasMessageGetNext",
+ gas_message.result);
+ return false;
+ }
+ }
+ // no break ...
+ default:
+ interface_error("GasActivity",result);
+ }
+ }
+ return true;
+}
+
+STR_String NG_TerraplayNetworkDeviceInterface::GetNetworkVersion()
+{
+ GASRString version = GAS->Version();
+ if (version.result != GASOK) {
+ interface_error("GetNetworkVersion", version.result);
+ return NULL;
+ } else {
+ return version.ptr;
+ }
+}
+
+int NG_TerraplayNetworkDeviceInterface::mytest() {
+ return (3);
+}
+
+void NG_TerraplayNetworkDeviceInterface::SendNetworkMessage(NG_NetworkMessage* nwmsg)
+{
+ GASPayload payload;
+ GASResult result;
+ STR_String mystring;
+
+ if (group_id == GASCLIENTIDNULL) {
+ printf("Oops, no group to send to yet\n");
+ return;
+ }
+
+ mystring = nwmsg->GetMessageText().ReadPtr();
+ payload.ptr = (void *) mystring.Ptr();
+ payload.size = mystring.Length() + 1;
+
+ result = GAS->ClientMessageSend(group_id, payload, GASBESTEFFORT);
+
+ switch (result) {
+ case GASOK:
+ break;
+ default:
+ interface_error("ClientMessageSend",result);
+ }
+ // NOTE. You shall NOT free the payload with PayloadFree().
+ // This is your own payload, allocated and freed by yourself
+ // anyway you want.
+}
+
+vector <NG_NetworkMessage*> NG_TerraplayNetworkDeviceInterface::RetrieveNetworkMessages()
+{
+
+ vector <NG_NetworkMessage*> messages;
+ //todo: spend your expensive time here!
+
+ return messages;
+}
diff --git a/source/gameengine/Network/TerraplayNetwork/NG_TerraplayNetworkDeviceInterface.h b/source/gameengine/Network/TerraplayNetwork/NG_TerraplayNetworkDeviceInterface.h
new file mode 100644
index 00000000000..384d70838a2
--- /dev/null
+++ b/source/gameengine/Network/TerraplayNetwork/NG_TerraplayNetworkDeviceInterface.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 *****
+ * TerraplayNetworkDeviceInterface derived from NG_NetworkDeviceInterface
+ */
+#ifndef NG_TERRAPLAYNETWORKDEVICEINTERFACE_H
+#define NG_TERRAPLAYNETWORKDEVICEINTERFACE_H
+
+#include <deque>
+#include "GASInterface.h"
+#include "NG_NetworkDeviceInterface.h"
+
+class NG_TerraplayNetworkDeviceInterface : public NG_NetworkDeviceInterface
+{
+ std::deque<NG_NetworkMessage*> m_messages;
+
+ // Terraplay GAS stuff
+ GASInterface *GAS;
+ GASClientId group_id;
+ GASRequestId group_id_request;
+ int group_id_request_valid;
+
+ void interface_error(char *str, GASResult error);
+public:
+ NG_TerraplayNetworkDeviceInterface();
+ ~NG_TerraplayNetworkDeviceInterface();
+
+ bool Connect(char *GAS_address, unsigned int GAS_port,
+ char *GAS_password, unsigned int localport,
+ unsigned int timeout);
+ bool Disconnect(void);
+
+ void SendNetworkMessage(NG_NetworkMessage* nwmsg);
+ vector<NG_NetworkMessage*> RetrieveNetworkMessages(void);
+
+ STR_String GetNetworkVersion(void);
+
+ int mytest(void);
+};
+
+#endif //NG_TERRAPLAYNETWORKDEVICEINTERFACE_H
+
diff --git a/source/gameengine/Physics/BlOde/Makefile b/source/gameengine/Physics/BlOde/Makefile
new file mode 100644
index 00000000000..b85c8b13bc4
--- /dev/null
+++ b/source/gameengine/Physics/BlOde/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 = blode
+DIR = $(OCGDIR)/gameengine/blphys/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO)/include -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_ODE)/include
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../Physics/common
+CPPFLAGS += -I../../Physics/Dummy
+# nlin: fix this, should put in NAN_ODE dir
+#CPPFLAGS += -I./ode/ode/include
diff --git a/source/gameengine/Physics/BlOde/OdePhysicsController.cpp b/source/gameengine/Physics/BlOde/OdePhysicsController.cpp
new file mode 100644
index 00000000000..a0fe068ab5c
--- /dev/null
+++ b/source/gameengine/Physics/BlOde/OdePhysicsController.cpp
@@ -0,0 +1,622 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * The contents of this file may be used under the terms of either the GNU
+ * General Public License Version 2 or later (the "GPL", see
+ * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or
+ * later (the "BL", see http://www.blender.org/BL/ ) which has to be
+ * bought from the Blender Foundation to become active, in which case the
+ * above mentioned GPL option does not apply.
+ *
+ * The Original Code is Copyright (C) 2002 by 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 USE_ODE
+#ifdef USE_ODE
+
+#include "OdePhysicsController.h"
+#include "PHY_IMotionState.h"
+
+#include <ode/ode.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+//
+// general to-do list for ODE physics. This is maintained in doxygen format.
+//
+/// \todo determine assignment time for bounding spheres.
+///
+/// it appears you have to select "sphere" for bounding volume AND "draw bounds"
+/// in order for a bounding sphere to be generated. otherwise a box is generated.
+/// determine exactly when and how the bounding volumes are generated and make
+/// this consistent.
+/// }
+///
+/// \todo bounding sphere size incorrect
+///
+/// it appears NOT to use the size of the shown bounding sphere (button "draw bounds").
+/// it appears instead to use the size of the "size" dynamic parameter in the
+/// gamebuttons but this "size" draws an incorrectly-sized circle on screen for the
+/// bounding sphere (leftover skewed size calculation from sumo?) so figure out WHERE
+/// its getting the radius from.
+///
+/// \todo ODE collisions must fire collision actuator
+///
+/// See OdePhysicsEnvironment::OdeNearCallback. If a sensor was created to check
+/// for the presence of this collision, then in the NearCallback you need to
+/// take appropriate action regarding the sensor - something like checking its
+/// controller and if needed firing its actuator. Need to find similar code in
+/// Fuzzics which fires collision controllers/actuators.
+///
+/// \todo Are ghost collisions possible?
+///
+/// How do ghost collisions work? Do they require collision detection through ODE
+/// and NON-CREATION of contact-joint in OdeNearCallback? Currently OdeNearCallback
+/// creates joints ALWAYS for collisions.
+///
+/// \todo Why is KX_GameObject::addLinearVelocity commented out?
+///
+/// Try putting this code back in.
+///
+/// \todo Too many non-dynamic actors bogs down ODE physics
+///
+/// Lots of "geoms" (ODE static geometry) probably slows down ode. Try a test file
+/// with lots of static geometry - the game performance in Blender says it is
+/// spending all its time in physics, and I bet all that time is in collision
+/// detection. It's ode's non-hierarchical collision detection.
+/// try making a separate ode test program (not within blender) with 1000 geoms and
+/// see how fast it is. if it is really slow, there is the culprit.
+/// isnt someone working on an improved ODE collision detector? check
+/// ode mailing list.
+///
+///
+/// \todo support collision of dynas with non-dynamic triangle meshes
+///
+/// ODE has trimesh-collision support but only for trimeshes without a transform
+/// matrix. update ODE tricollider to support a transform matrix. this will allow
+/// moving trimeshes non-dynamically (e.g. through Ipos). then collide trimeshes
+/// with dynas. this allows dynamic primitives (spheres, boxes) to collide with
+/// non-dynamic or kinematically controlled tri-meshes. full dynamic trimesh to
+/// dynamic trimesh support is hard because it requires (a) collision and penetration
+/// depth for trimesh to trimesh and (hard to compute) (b) an intertia tensor
+/// (easy to compute).
+///
+/// a triangle mesh collision geometry should be created when the blender
+/// bounding volume (F9, EDITBUTTONS) is set to "polyheder", since this is
+/// currently the place where sphere/box selection is made
+///
+/// \todo specify ODE ERP+CFM in blender interface
+///
+/// when ODE physics selected, have to be able to set global cfm and erp.
+/// per-joint erp/cfm could be handled in constraint window.
+///
+/// \todo moving infinite mass objects should impart extra impulse to objects they collide with
+///
+/// currently ODE's ERP pushes them apart but doesn't account for their motion.
+/// you have to detect if one body in a collision is a non-dyna. This
+/// requires adding a new accessor method to
+/// KX_IPhysicsInterfaceController to access the hidden m_isDyna variable,
+/// currently it can only be written, not read). If one of the bodies in a
+/// collision is a non-dyna, then impart an extra impulse based on the
+/// motion of the static object (using its last 2 frames as an approximation
+/// of its linear and angular velocity). Linear velocity is easy to
+/// approximate, but angular? you have orientation at this frame and
+/// orientation at previous frame. The question is what is the angular
+/// velocity which would have taken you from the previous frame's orientation
+/// to this frame's orientation?
+///
+/// \todo allow tweaking bounding volume size
+///
+/// the scene converter currently uses the blender bounding volume of the selected
+/// object as the geometry for ODE collision purposes. this is good and automatic
+/// intuitive - lets you choose between cube, sphere, mesh. but you need to be able
+/// to tweak this size for physics.
+///
+/// \todo off center meshes totally wrong for ode
+///
+/// ode uses x, y, z extents regradless of center. then places geom at center of object.
+/// but visual geom is not necessarily at center. need to detect off-center situations.
+/// then do what? treat it as an encapsulated off-center mass, or recenter it?
+///
+/// i.o.w. recalculate center, or recalculate mass distribution (using encapsulation)?
+///
+/// \todo allow off-center mass
+///
+/// using ode geometry encapsulators
+///
+/// \todo allow entering compound geoms for complex collision shapes specified as a union of simpler shapes
+///
+/// The collision shape for arbitrary triangle meshes can probably in general be
+///well approximated by a compound ODE geometry object, which is merely a combination
+///of many primitives (capsule, sphere, box). I eventually want to add the ability
+///to associate compound geometry objects with Blender gameobjects. I think one
+///way of doing this would be to add a new button in the GameButtons, "RigidBodyCompound".
+///If the object is "Dynamic" + "RigidBody", then the object's bounding volume (sphere,
+///box) is created. If an object is "Dynamic" + "RigidBodyCompound", then the object itself
+///will merely create a "wrapper" compound object, with the actual geometry objects
+///being created from the object's children in Blender. E.g. if I wanted to make a
+///compound collision object consisting of a sphere and 2 boxes, I would create a
+///parent gameobject with the actual triangle mesh, and set its GameButtons to
+///"RigidBodyCompound". I would then create 3 children of this object, 1 sphere and
+///2 boxes, and set the GameButtons for the children to be "RigidBody". Then at
+///scene conversion time, the scene converter sees "RigidBodyCompound" for the
+///top-level object, then appropriately traverses the children and creates the compound
+///collision geometry consisting of 2 boxes and a sphere. In this way, arbitrary
+///mesh-mesh collision becomes much less necessary - the artist can (or must,
+///depending on your point of view!) approximate the collision shape for arbitrary
+///meshes with a combination of one or more primitive shapes. I think using the
+///parent/child relationship in Blender and a new button "RigidBodyCompound" for the
+///parent object of a compound is a feasible way of doing this in Blender.
+///
+///See ODE demo test_boxstack and look at the code when you drop a compound object
+///with the "X" key.
+///
+/// \todo add visual specification of constraints
+///
+/// extend the armature constraint system. by using empties and constraining one empty
+/// to "copy location" of another, you can get a p2p constraint between the two empties.
+/// by making the two empties each a parent of a blender object, you effectively have
+/// a p2p constraint between 2 blender bodies. the scene converter can detect these
+/// empties, detect the constraint, and generate an ODE constraint.
+///
+/// then add a new constraint type "hinge" and "slider" to correspond to ODE joints.
+/// e.g. a slider would be a constraint which restricts the axis of its object to lie
+/// along the same line as another axis of a different object. e.g. you constrain x-axis
+/// of one empty to lie along the same line as the z-axis of another empty; this gives
+/// a slider joint.
+///
+/// open questions: how to handle powered joints? to what extent should/must constraints
+/// be enforced during modeling? use CCD-style algorithm in modeler to enforce constraints?
+/// how about ODE powered constraints e.g. motors?
+///
+/// \todo enable suspension of bodies
+/// ODE offers native support for suspending dynas. but what about suspending non-dynas
+/// (e.g. geoms)? suspending geoms is also necessary to ease the load of ODE's (simple?)
+/// collision detector. suspending dynas and geoms is important for the activity culling,
+/// which apparently works at a simple level. perhaps suspension should actually
+/// remove or insert geoms/dynas into the ODE space/world? is this operation (insertion/
+/// removal) fast enough at run-time? test it. if fast enough, then suspension=remove from
+/// ODE simulation, awakening=insertion into ODE simulation.
+///
+/// \todo python interface for tweaking constraints via python
+///
+/// \todo raytesting to support gameengine sensors that need it
+///
+/// \todo investigate compatibility issues with old Blender 2.25 physics engine (sumo/fuzzics)
+/// is it possible to have compatibility? how hard is it? how important is it?
+
+
+ODEPhysicsController::ODEPhysicsController(bool dyna, bool fullRigidBody,
+ bool phantom, class PHY_IMotionState* motionstate, struct dxSpace* space,
+ struct dxWorld* world, float mass,float friction,float restitution,
+ bool implicitsphere,float center[3],float extents[3],float radius)
+ :
+ m_OdeDyna(dyna),
+ m_firstTime(true),
+ m_bFullRigidBody(fullRigidBody),
+ m_bPhantom(phantom),
+ m_bKinematic(false),
+ m_bPrevKinematic(false),
+ m_MotionState(motionstate),
+ m_OdeSuspendDynamics(false),
+ m_space(space),
+ m_world(world),
+ m_mass(mass),
+ m_friction(friction),
+ m_restitution(restitution),
+ m_bodyId(0),
+ m_geomId(0),
+ m_implicitsphere(implicitsphere),
+ m_radius(radius)
+{
+ m_center[0] = center[0];
+ m_center[1] = center[1];
+ m_center[2] = center[2];
+ m_extends[0] = extents[0];
+ m_extends[1] = extents[1];
+ m_extends[2] = extents[2];
+};
+
+
+ODEPhysicsController::~ODEPhysicsController()
+{
+ if (m_geomId)
+ {
+ dGeomDestroy (m_geomId);
+ }
+}
+
+float ODEPhysicsController::getMass()
+{
+ dMass mass;
+ dBodyGetMass(m_bodyId,&mass);
+ return mass.mass;
+}
+
+//////////////////////////////////////////////////////////////////////
+/// \todo Impart some extra impulse to dynamic objects when they collide with kinematically controlled "static" objects (ODE geoms), by using last 2 frames as 1st order approximation to the linear/angular velocity, and computing an appropriate impulse. Sumo (old physics engine) did this, see for details.
+/// \todo handle scaling of static ODE geoms or fail with error message if Ipo tries to change scale of a static geom object
+
+bool ODEPhysicsController::SynchronizeMotionStates(float time)
+{
+ /**
+ 'Late binding' of the rigidbody, because the World Scaling is not available until the scenegraph is traversed
+ */
+
+
+ if (m_firstTime)
+ {
+ m_firstTime=false;
+
+ m_MotionState->calculateWorldTransformations();
+
+ dQuaternion worldquat;
+ float worldpos[3];
+
+#ifdef dDOUBLE
+ m_MotionState->getWorldOrientation((float)worldquat[1],
+ (float)worldquat[2],(float)worldquat[3],(float)worldquat[0]);
+#else
+ m_MotionState->getWorldOrientation(worldquat[1],
+ worldquat[2],worldquat[3],worldquat[0]);
+#endif
+ m_MotionState->getWorldPosition(worldpos[0],worldpos[1],worldpos[2]);
+
+ float scaling[3];
+ m_MotionState->getWorldScaling(scaling[0],scaling[1],scaling[2]);
+
+ if (!m_bPhantom)
+ {
+ if (m_implicitsphere)
+ {
+ m_geomId = dCreateSphere (m_space,m_radius*scaling[0]);
+ } else
+ {
+ m_geomId = dCreateBox (m_space, m_extends[0]*scaling[0],m_extends[1]*scaling[1],m_extends[2]*scaling[2]);
+ }
+ } else
+ {
+ m_geomId=0;
+ }
+
+ if (m_geomId)
+ dGeomSetData(m_geomId,this);
+
+ if (!this->m_OdeDyna)
+ {
+ if (!m_bPhantom)
+ {
+ dGeomSetPosition (this->m_geomId,worldpos[0],worldpos[1],worldpos[2]);
+ dMatrix3 R;
+ dQtoR (worldquat, R);
+ dGeomSetRotation (this->m_geomId,R);
+ }
+ } else
+ {
+ //it's dynamic, so create a 'model'
+ m_bodyId = dBodyCreate(this->m_world);
+ dBodySetPosition (m_bodyId,worldpos[0],worldpos[1],worldpos[2]);
+ dBodySetQuaternion (this->m_bodyId,worldquat);
+ //this contains both scalar mass and inertia tensor
+ dMass m;
+ float length=1,width=1,height=1;
+ dMassSetBox (&m,1,m_extends[0]*scaling[0],m_extends[1]*scaling[1],m_extends[2]*scaling[2]);
+ dMassAdjust (&m,this->m_mass);
+ dBodySetMass (m_bodyId,&m);
+
+ if (!m_bPhantom)
+ {
+ dGeomSetBody (m_geomId,m_bodyId);
+ }
+
+
+ }
+
+ if (this->m_OdeDyna && !m_bFullRigidBody)
+ {
+ // ?? huh? what to do here?
+ }
+ }
+
+
+
+ if (m_OdeDyna)
+ {
+ if (this->m_OdeSuspendDynamics)
+ {
+ return false;
+ }
+
+ const float* worldPos = (float *)dBodyGetPosition(m_bodyId);
+ m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]);
+
+ const float* worldquat = (float *)dBodyGetQuaternion(m_bodyId);
+ m_MotionState->setWorldOrientation(worldquat[1],worldquat[2],worldquat[3],worldquat[0]);
+ }
+ else {
+ // not a dyna, so dynamics (i.e. this controller) has not updated
+ // anything. BUT! an Ipo or something else might have changed the
+ // position/orientation of this geometry.
+ // so update the static geom position
+
+ /// \todo impart some extra impulse to colliding objects!
+ dQuaternion worldquat;
+ float worldpos[3];
+
+#ifdef dDOUBLE
+ m_MotionState->getWorldOrientation((float)worldquat[1],
+ (float)worldquat[2],(float)worldquat[3],(float)worldquat[0]);
+#else
+ m_MotionState->getWorldOrientation(worldquat[1],
+ worldquat[2],worldquat[3],worldquat[0]);
+#endif
+ m_MotionState->getWorldPosition(worldpos[0],worldpos[1],worldpos[2]);
+
+ float scaling[3];
+ m_MotionState->getWorldScaling(scaling[0],scaling[1],scaling[2]);
+
+ /// \todo handle scaling! what if Ipo changes scale of object?
+ // Must propagate to geom... is scaling geoms possible with ODE? Also
+ // what about scaling trimeshes, that is certainly difficult...
+ dGeomSetPosition (this->m_geomId,worldpos[0],worldpos[1],worldpos[2]);
+ dMatrix3 R;
+ dQtoR (worldquat, R);
+ dGeomSetRotation (this->m_geomId,R);
+ }
+
+ return false; //it update the worldpos
+}
+
+
+
+
+// kinematic methods
+void ODEPhysicsController::RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local)
+{
+
+}
+void ODEPhysicsController::RelativeRotate(const float drot[9],bool local)
+{
+}
+void ODEPhysicsController::setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal)
+{
+
+ dQuaternion worldquat;
+ worldquat[0] = quatReal;
+ worldquat[1] = quatImag0;
+ worldquat[2] = quatImag1;
+ worldquat[3] = quatImag2;
+
+ if (!this->m_OdeDyna)
+ {
+ dMatrix3 R;
+ dQtoR (worldquat, R);
+ dGeomSetRotation (this->m_geomId,R);
+ } else
+ {
+ dBodySetQuaternion (m_bodyId,worldquat);
+ this->m_MotionState->setWorldOrientation(quatImag0,quatImag1,quatImag2,quatReal);
+ }
+
+}
+
+void ODEPhysicsController::getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal)
+{
+ float q[4];
+ this->m_MotionState->getWorldOrientation(q[0],q[1],q[2],q[3]);
+ quatImag0=q[0];
+ quatImag1=q[1];
+ quatImag2=q[2];
+ quatReal=q[3];
+}
+
+void ODEPhysicsController::getPosition(PHY__Vector3& pos) const
+{
+ m_MotionState->getWorldPosition(pos[0],pos[1],pos[2]);
+
+}
+
+void ODEPhysicsController::setPosition(float posX,float posY,float posZ)
+{
+ if (!m_bPhantom)
+ {
+ if (!this->m_OdeDyna)
+ {
+ dGeomSetPosition (m_geomId, posX, posY, posZ);
+ } else
+ {
+ dBodySetPosition (m_bodyId, posX, posY, posZ);
+ }
+ }
+}
+void ODEPhysicsController::setScaling(float scaleX,float scaleY,float scaleZ)
+{
+}
+
+// physics methods
+void ODEPhysicsController::ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local)
+{
+ if (m_OdeDyna) {
+ if(local) {
+ dBodyAddRelTorque(m_bodyId, torqueX, torqueY, torqueZ);
+ } else {
+ dBodyAddTorque (m_bodyId, torqueX, torqueY, torqueZ);
+ }
+ }
+}
+
+void ODEPhysicsController::ApplyForce(float forceX,float forceY,float forceZ,bool local)
+{
+ if (m_OdeDyna) {
+ if(local) {
+ dBodyAddRelForce(m_bodyId, forceX, forceY, forceZ);
+ } else {
+ dBodyAddForce (m_bodyId, forceX, forceY, forceZ);
+ }
+ }
+}
+
+void ODEPhysicsController::SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local)
+{
+ if (m_OdeDyna) {
+ if(local) {
+ // TODO: translate angular vel into local frame, then apply
+ } else {
+ dBodySetAngularVel (m_bodyId, ang_velX,ang_velY,ang_velZ);
+ }
+ }
+}
+
+void ODEPhysicsController::SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local)
+{
+ if (m_OdeDyna)
+ {
+ dVector3 vel = {lin_velX,lin_velY,lin_velZ, 1.0};
+ if (local)
+ {
+ dMatrix3 worldmat;
+ dVector3 localvel;
+ dQuaternion worldquat;
+
+#ifdef dDOUBLE
+ m_MotionState->getWorldOrientation((float)worldquat[1],
+ (float)worldquat[2], (float)worldquat[3],(float)worldquat[0]);
+#else
+ m_MotionState->getWorldOrientation(worldquat[1],worldquat[2],
+ worldquat[3],worldquat[0]);
+#endif
+ dQtoR (worldquat, worldmat);
+
+ dMULTIPLY0_331 (localvel,worldmat,vel);
+ dBodySetLinearVel (m_bodyId, localvel[0],localvel[1],localvel[2]);
+
+ } else
+ {
+ dBodySetLinearVel (m_bodyId, lin_velX,lin_velY,lin_velZ);
+ }
+ }
+}
+
+void ODEPhysicsController::applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ)
+{
+ if (m_OdeDyna)
+ {
+ //apply linear and angular effect
+ const dReal* linvel = dBodyGetLinearVel(m_bodyId);
+ float mass = getMass();
+ if (mass >= 0.00001f)
+ {
+ float massinv = 1.f/mass;
+ float newvel[3];
+ newvel[0]=linvel[0]+impulseX*massinv;
+ newvel[1]=linvel[1]+impulseY*massinv;
+ newvel[2]=linvel[2]+impulseZ*massinv;
+ dBodySetLinearVel(m_bodyId,newvel[0],newvel[1],newvel[2]);
+
+ const float* worldPos = (float *)dBodyGetPosition(m_bodyId);
+
+ const float* angvelc = (float *)dBodyGetAngularVel(m_bodyId);
+ float angvel[3];
+ angvel[0]=angvelc[0];
+ angvel[1]=angvelc[1];
+ angvel[2]=angvelc[2];
+
+ dVector3 impulse;
+ impulse[0]=impulseX;
+ impulse[1]=impulseY;
+ impulse[2]=impulseZ;
+
+ dVector3 ap;
+ ap[0]=attachX-worldPos[0];
+ ap[1]=attachY-worldPos[1];
+ ap[2]=attachZ-worldPos[2];
+
+ dCROSS(angvel,+=,ap,impulse);
+ dBodySetAngularVel(m_bodyId,angvel[0],angvel[1],angvel[2]);
+
+ }
+
+ }
+
+}
+
+void ODEPhysicsController::SuspendDynamics()
+{
+
+}
+
+void ODEPhysicsController::RestoreDynamics()
+{
+
+}
+
+
+/**
+ reading out information from physics
+*/
+void ODEPhysicsController::GetLinearVelocity(float& linvX,float& linvY,float& linvZ)
+{
+ if (m_OdeDyna)
+ {
+ const float* vel = (float *)dBodyGetLinearVel(m_bodyId);
+ linvX = vel[0];
+ linvY = vel[1];
+ linvZ = vel[2];
+ } else
+ {
+ linvX = 0.f;
+ linvY = 0.f;
+ linvZ = 0.f;
+
+ }
+}
+/**
+ GetVelocity parameters are in geometric coordinates (Origin is not center of mass!).
+*/
+void ODEPhysicsController::GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ)
+{
+
+}
+
+
+void ODEPhysicsController::getReactionForce(float& forceX,float& forceY,float& forceZ)
+{
+
+}
+void ODEPhysicsController::setRigidBody(bool rigid)
+{
+
+}
+
+
+void ODEPhysicsController::PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl)
+{
+ m_MotionState = motionstate;
+ m_bKinematic = false;
+ m_bPrevKinematic = false;
+ m_firstTime = true;
+}
+
+
+void ODEPhysicsController::SetSimulatedTime(float time)
+{
+}
+
+
+void ODEPhysicsController::WriteMotionStateToDynamics(bool nondynaonly)
+{
+
+}
+#endif
diff --git a/source/gameengine/Physics/BlOde/OdePhysicsController.h b/source/gameengine/Physics/BlOde/OdePhysicsController.h
new file mode 100644
index 00000000000..4f4acb5cd18
--- /dev/null
+++ b/source/gameengine/Physics/BlOde/OdePhysicsController.h
@@ -0,0 +1,157 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * The contents of this file may be used under the terms of either the GNU
+ * General Public License Version 2 or later (the "GPL", see
+ * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or
+ * later (the "BL", see http://www.blender.org/BL/ ) which has to be
+ * bought from the Blender Foundation to become active, in which case the
+ * above mentioned GPL option does not apply.
+ *
+ * The Original Code is Copyright (C) 2002 by 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 __ODE_PHYSICSCONTROLLER_H
+#define __ODE_PHYSICSCONTROLLER_H
+
+
+#include "PHY_IPhysicsController.h"
+
+/**
+ ODE Physics Controller, a special kind of a PhysicsController.
+ A Physics Controller is a special kind of Scene Graph Transformation Controller.
+ Each time the scene graph get's updated, the controller get's a chance
+ in the 'Update' method to reflect changes.
+*/
+
+class ODEPhysicsController : public PHY_IPhysicsController
+
+{
+
+ bool m_OdeDyna;
+
+public:
+ ODEPhysicsController(
+ bool dyna,
+ bool fullRigidBody,
+ bool phantom,
+ class PHY_IMotionState* motionstate,
+ struct dxSpace* space,
+ struct dxWorld* world,
+ float mass,
+ float friction,
+ float restitution,
+ bool implicitsphere,
+ float center[3],
+ float extends[3],
+ float radius);
+
+ virtual ~ODEPhysicsController();
+
+ // kinematic methods
+ virtual void RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local);
+ virtual void RelativeRotate(const float drot[9],bool local);
+ virtual void getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal);
+ virtual void setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal);
+ virtual void setPosition(float posX,float posY,float posZ);
+ virtual void getPosition(PHY__Vector3& pos) const;
+
+ virtual void setScaling(float scaleX,float scaleY,float scaleZ);
+
+ // physics methods
+ virtual void ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local);
+ virtual void ApplyForce(float forceX,float forceY,float forceZ,bool local);
+ virtual void SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local);
+ virtual void SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local);
+ virtual void applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ);
+ virtual void SetActive(bool active){};
+ virtual void SuspendDynamics();
+ virtual void RestoreDynamics();
+ virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ)
+ {
+ //todo ?
+ }
+
+
+ /**
+ reading out information from physics
+ */
+ virtual void GetLinearVelocity(float& linvX,float& linvY,float& linvZ);
+ /**
+ GetVelocity parameters are in geometric coordinates (Origin is not center of mass!).
+ */
+ virtual void GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ);
+ virtual float getMass();
+ virtual void getReactionForce(float& forceX,float& forceY,float& forceZ);
+ virtual void setRigidBody(bool rigid);
+
+
+ virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl);
+
+ // \todo remove next line !
+ virtual void SetSimulatedTime(float time);
+
+
+ virtual void WriteDynamicsToMotionState() {};
+ virtual void WriteMotionStateToDynamics(bool nondynaonly);
+
+ /**
+ call from Scene Graph Node to 'update'.
+ */
+ virtual bool SynchronizeMotionStates(float time);
+
+ virtual void calcXform(){}
+ virtual void SetMargin(float margin) {}
+ virtual float GetMargin() const {return 0.f;}
+
+ // clientinfo for raycasts for example
+ virtual void* getNewClientInfo() { return m_clientInfo;}
+ virtual void setNewClientInfo(void* clientinfo) {m_clientInfo = clientinfo;};
+ void* m_clientInfo;
+
+ struct dxBody* GetOdeBodyId() { return m_bodyId; }
+
+ float getFriction() { return m_friction;}
+ float getRestitution() { return m_restitution;}
+
+
+
+private:
+
+ bool m_firstTime;
+ bool m_bFullRigidBody;
+ bool m_bPhantom; // special flag for objects that are not affected by physics 'resolver'
+
+ // data to calculate fake velocities for kinematic objects (non-dynas)
+ bool m_bKinematic;
+ bool m_bPrevKinematic;
+
+
+ float m_lastTime;
+ bool m_OdeSuspendDynamics;
+ class PHY_IMotionState* m_MotionState;
+
+ //Ode specific members
+ struct dxBody* m_bodyId;
+ struct dxGeom* m_geomId;
+ struct dxSpace* m_space;
+ struct dxWorld* m_world;
+ float m_mass;
+ float m_friction;
+ float m_restitution;
+ bool m_implicitsphere;
+ float m_center[3];
+ float m_extends[3];
+ float m_radius;
+};
+
+#endif //__ODE_PHYSICSCONTROLLER_H
+
diff --git a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp
new file mode 100644
index 00000000000..f6382ec775c
--- /dev/null
+++ b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp
@@ -0,0 +1,278 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * The contents of this file may be used under the terms of either the GNU
+ * General Public License Version 2 or later (the "GPL", see
+ * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or
+ * later (the "BL", see http://www.blender.org/BL/ ) which has to be
+ * bought from the Blender Foundation to become active, in which case the
+ * above mentioned GPL option does not apply.
+ *
+ * The Original Code is Copyright (C) 2002 by 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 "OdePhysicsEnvironment.h"
+#include "PHY_IMotionState.h"
+#include "OdePhysicsController.h"
+
+#include <ode/ode.h>
+#include <../ode/src/joint.h>
+#include <ode/odemath.h>
+
+ODEPhysicsEnvironment::ODEPhysicsEnvironment()
+{
+ m_OdeWorld = dWorldCreate();
+ m_OdeSpace = dHashSpaceCreate();
+ m_OdeContactGroup = dJointGroupCreate (0);
+ dWorldSetCFM (m_OdeWorld,1e-5f);
+
+ m_JointGroup = dJointGroupCreate(0);
+
+ setFixedTimeStep(true,1.f/60.f);
+}
+
+
+
+ODEPhysicsEnvironment::~ODEPhysicsEnvironment()
+{
+ dJointGroupDestroy (m_OdeContactGroup);
+ dJointGroupDestroy (m_JointGroup);
+
+ dSpaceDestroy (m_OdeSpace);
+ dWorldDestroy (m_OdeWorld);
+}
+
+
+
+void ODEPhysicsEnvironment::setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep)
+{
+ m_useFixedTimeStep = useFixedTimeStep;
+
+ if (useFixedTimeStep)
+ {
+ m_fixedTimeStep = fixedTimeStep;
+ } else
+ {
+ m_fixedTimeStep = 0.f;
+ }
+ m_currentTime = 0.f;
+
+ //todo:implement fixed timestepping
+
+}
+float ODEPhysicsEnvironment::getFixedTimeStep()
+{
+ return m_fixedTimeStep;
+}
+
+
+
+bool ODEPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep1)
+{
+
+ float deltaTime = timeStep1;
+ int numSteps = 1;
+
+ if (m_useFixedTimeStep)
+ {
+ m_currentTime += timeStep1;
+ // equal to subSampling (might be a little smaller).
+ numSteps = (int)(m_currentTime / m_fixedTimeStep);
+ m_currentTime -= m_fixedTimeStep * (float)numSteps;
+ deltaTime = m_fixedTimeStep;
+ //todo: experiment by smoothing the remaining time over the substeps
+ }
+
+ for (int i=0;i<numSteps;i++)
+ {
+ // ode collision update
+ dSpaceCollide (m_OdeSpace,this,&ODEPhysicsEnvironment::OdeNearCallback);
+
+ int m_odeContacts = GetNumOdeContacts();
+
+ //physics integrator + resolver update
+ //dWorldStep (m_OdeWorld,deltaTime);
+ //dWorldQuickStep (m_OdeWorld,deltaTime);
+ //dWorldID w, dReal stepsize)
+
+ //clear collision points
+ this->ClearOdeContactGroup();
+ }
+ return true;
+}
+
+void ODEPhysicsEnvironment::setGravity(float x,float y,float z)
+{
+ dWorldSetGravity (m_OdeWorld,x,y,z);
+}
+
+
+
+int ODEPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type,
+ float pivotX,float pivotY,float pivotZ,float axisX,float axisY,float axisZ)
+{
+
+ int constraintid = 0;
+ ODEPhysicsController* dynactrl = (ODEPhysicsController*)ctrl;
+ ODEPhysicsController* dynactrl2 = (ODEPhysicsController*)ctrl2;
+
+ switch (type)
+ {
+ case PHY_POINT2POINT_CONSTRAINT:
+ {
+ if (dynactrl)
+ {
+ dJointID jointid = dJointCreateBall (m_OdeWorld,m_JointGroup);
+ struct dxBody* bodyid1 = dynactrl->GetOdeBodyId();
+ struct dxBody* bodyid2=0;
+ const dReal* pos = dBodyGetPosition(bodyid1);
+ const dReal* R = dBodyGetRotation(bodyid1);
+ dReal offset[3] = {pivotX,pivotY,pivotZ};
+ dReal newoffset[3];
+ dMULTIPLY0_331 (newoffset,R,offset);
+ newoffset[0] += pos[0];
+ newoffset[1] += pos[1];
+ newoffset[2] += pos[2];
+
+
+ if (dynactrl2)
+ bodyid2 = dynactrl2->GetOdeBodyId();
+
+ dJointAttach (jointid, bodyid1, bodyid2);
+
+ dJointSetBallAnchor (jointid, newoffset[0], newoffset[1], newoffset[2]);
+
+ constraintid = (int) jointid;
+ }
+ break;
+ }
+ case PHY_LINEHINGE_CONSTRAINT:
+ {
+ if (dynactrl)
+ {
+ dJointID jointid = dJointCreateHinge (m_OdeWorld,m_JointGroup);
+ struct dxBody* bodyid1 = dynactrl->GetOdeBodyId();
+ struct dxBody* bodyid2=0;
+ const dReal* pos = dBodyGetPosition(bodyid1);
+ const dReal* R = dBodyGetRotation(bodyid1);
+ dReal offset[3] = {pivotX,pivotY,pivotZ};
+ dReal axisset[3] = {axisX,axisY,axisZ};
+
+ dReal newoffset[3];
+ dReal newaxis[3];
+ dMULTIPLY0_331 (newaxis,R,axisset);
+
+ dMULTIPLY0_331 (newoffset,R,offset);
+ newoffset[0] += pos[0];
+ newoffset[1] += pos[1];
+ newoffset[2] += pos[2];
+
+
+ if (dynactrl2)
+ bodyid2 = dynactrl2->GetOdeBodyId();
+
+ dJointAttach (jointid, bodyid1, bodyid2);
+
+ dJointSetHingeAnchor (jointid, newoffset[0], newoffset[1], newoffset[2]);
+ dJointSetHingeAxis(jointid,newaxis[0],newaxis[1],newaxis[2]);
+
+ constraintid = (int) jointid;
+ }
+ break;
+ }
+ default:
+ {
+ //not yet
+ }
+ }
+
+ return constraintid;
+
+}
+
+void ODEPhysicsEnvironment::removeConstraint(int constraintid)
+{
+ if (constraintid)
+ {
+ dJointDestroy((dJointID) constraintid);
+ }
+}
+
+PHY_IPhysicsController* ODEPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ,
+ float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ)
+{
+
+ //m_OdeWorld
+ //collision detection / raytesting
+ return NULL;
+}
+
+
+void ODEPhysicsEnvironment::OdeNearCallback (void *data, dGeomID o1, dGeomID o2)
+{
+ // \todo if this is a registered collision sensor
+ // fire the callback
+
+ int i;
+ // if (o1->body && o2->body) return;
+ ODEPhysicsEnvironment* env = (ODEPhysicsEnvironment*) data;
+ dBodyID b1,b2;
+
+ b1 = dGeomGetBody(o1);
+ b2 = dGeomGetBody(o2);
+ // exit without doing anything if the two bodies are connected by a joint
+ if (b1 && b2 && dAreConnected (b1,b2)) return;
+
+ ODEPhysicsController * ctrl1 =(ODEPhysicsController *)dGeomGetData(o1);
+ ODEPhysicsController * ctrl2 =(ODEPhysicsController *)dGeomGetData(o2);
+ float friction=ctrl1->getFriction();
+ float restitution = ctrl1->getRestitution();
+ //for friction, take minimum
+
+ friction=(friction < ctrl2->getFriction() ?
+ friction :ctrl2->getFriction());
+
+ //restitution:take minimum
+ restitution = restitution < ctrl2->getRestitution()?
+ restitution : ctrl2->getRestitution();
+
+ dContact contact[3]; // up to 3 contacts per box
+ for (i=0; i<3; i++) {
+ contact[i].surface.mode = dContactBounce; //dContactMu2;
+ contact[i].surface.mu = friction;//dInfinity;
+ contact[i].surface.mu2 = 0;
+ contact[i].surface.bounce = restitution;//0.5;
+ contact[i].surface.bounce_vel = 0.1f;
+ contact[i].surface.slip1=0.0;
+ }
+
+ if (int numc = dCollide (o1,o2,3,&contact[0].geom,sizeof(dContact))) {
+ // dMatrix3 RI;
+ // dRSetIdentity (RI);
+ // const dReal ss[3] = {0.02,0.02,0.02};
+ for (i=0; i<numc; i++) {
+ dJointID c = dJointCreateContact (env->m_OdeWorld,env->m_OdeContactGroup,contact+i);
+ dJointAttach (c,b1,b2);
+ }
+ }
+}
+
+
+void ODEPhysicsEnvironment::ClearOdeContactGroup()
+{
+ dJointGroupEmpty (m_OdeContactGroup);
+}
+
+int ODEPhysicsEnvironment::GetNumOdeContacts()
+{
+ return m_OdeContactGroup->num;
+}
+
diff --git a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h
new file mode 100644
index 00000000000..bddc1e03be1
--- /dev/null
+++ b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h
@@ -0,0 +1,93 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * The contents of this file may be used under the terms of either the GNU
+ * General Public License Version 2 or later (the "GPL", see
+ * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or
+ * later (the "BL", see http://www.blender.org/BL/ ) which has to be
+ * bought from the Blender Foundation to become active, in which case the
+ * above mentioned GPL option does not apply.
+ *
+ * The Original Code is Copyright (C) 2002 by 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 _ODEPHYSICSENVIRONMENT
+#define _ODEPHYSICSENVIRONMENT
+
+
+#include "PHY_IPhysicsEnvironment.h"
+
+/**
+* Physics Environment takes care of stepping the simulation and is a container for physics entities (rigidbodies,constraints, materials etc.)
+* A derived class may be able to 'construct' entities by loading and/or converting
+*/
+class ODEPhysicsEnvironment : public PHY_IPhysicsEnvironment
+{
+
+ bool m_useFixedTimeStep;
+ float m_fixedTimeStep;
+ float m_currentTime;
+
+public:
+ ODEPhysicsEnvironment();
+ virtual ~ODEPhysicsEnvironment();
+ virtual void beginFrame() {}
+ virtual void endFrame() {}
+
+
+// Perform an integration step of duration 'timeStep'.
+ virtual bool proceedDeltaTime(double curTime,float timeStep);
+ virtual void setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep);
+ virtual float getFixedTimeStep();
+
+ virtual void setGravity(float x,float y,float z);
+ virtual int createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type,
+ float pivotX,float pivotY,float pivotZ,
+ float axisX,float axisY,float axisZ);
+
+ virtual void removeConstraint(void * constraintid);
+ virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ,
+ float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ);
+
+
+ //gamelogic callbacks
+ virtual void addSensor(PHY_IPhysicsController* ctrl) {}
+ virtual void removeSensor(PHY_IPhysicsController* ctrl) {}
+ virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user)
+ {
+ }
+ virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl) {}
+ virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position) {return 0;}
+ virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight) { return 0;}
+
+
+
+ struct dxWorld* GetOdeWorld() { return m_OdeWorld; };
+ struct dxSpace* GetOdeSpace() { return m_OdeSpace;};
+
+private:
+
+
+ // ODE physics response
+ struct dxWorld* m_OdeWorld;
+ // ODE collision detection
+ struct dxSpace* m_OdeSpace;
+ void ClearOdeContactGroup();
+ struct dxJointGroup* m_OdeContactGroup;
+ struct dxJointGroup* m_JointGroup;
+
+ static void OdeNearCallback(void *data, struct dxGeom* o1, struct dxGeom* o2);
+ int GetNumOdeContacts();
+
+};
+
+#endif //_ODEPHYSICSENVIRONMENT
+
diff --git a/source/gameengine/Physics/BlOde/SConscript b/source/gameengine/Physics/BlOde/SConscript
new file mode 100644
index 00000000000..90e949d2d86
--- /dev/null
+++ b/source/gameengine/Physics/BlOde/SConscript
@@ -0,0 +1,15 @@
+#!/usr/bin/python
+Import ('user_options_dict')
+Import ('library_env')
+
+phy_ode_env = library_env.Copy ()
+
+source_files = ['OdePhysicsController.cpp',
+ 'OdePhysicsEnvironment.cpp']
+
+phy_ode_env.Append (CPPPATH=['.',
+ '../common',
+ ])
+phy_ode_env.Append (CPPPATH=user_options_dict['ODE_INCLUDE'])
+
+phy_ode_env.Library (target='#'+user_options_dict['BUILD_DIR']+'/lib/PHY_Ode', source=source_files)
diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt
new file mode 100644
index 00000000000..af67d4b126d
--- /dev/null
+++ b/source/gameengine/Physics/Bullet/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 *****
+
+SET(SRC CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp)
+
+SET(INC
+ .
+ ../common
+ ../../../../extern/bullet2/src
+)
+
+BLENDERLIB(bf_bullet "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_bullet', Split(sources), Split(incs), [], libtype=['game','player'], priority=[15,90] )
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
new file mode 100644
index 00000000000..5a45ce020cc
--- /dev/null
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
@@ -0,0 +1,636 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "CcdPhysicsController.h"
+#include "btBulletDynamicsCommon.h"
+
+#include "PHY_IMotionState.h"
+#include "CcdPhysicsEnvironment.h"
+
+
+class BP_Proxy;
+
+///todo: fill all the empty CcdPhysicsController methods, hook them up to the btRigidBody class
+
+//'temporarily' global variables
+//float gDeactivationTime = 2.f;
+//bool gDisableDeactivation = false;
+extern float gDeactivationTime;
+extern bool gDisableDeactivation;
+
+
+float gLinearSleepingTreshold = 0.8f;
+float gAngularSleepingTreshold = 1.0f;
+
+
+btVector3 startVel(0,0,0);//-10000);
+CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci)
+:m_cci(ci)
+{
+ m_collisionDelay = 0;
+ m_newClientInfo = 0;
+
+ m_MotionState = ci.m_MotionState;
+ m_bulletMotionState = 0;
+
+
+ CreateRigidbody();
+
+
+
+ #ifdef WIN32
+ if (m_body->getInvMass())
+ m_body->setLinearVelocity(startVel);
+ #endif
+
+}
+
+btTransform CcdPhysicsController::GetTransformFromMotionState(PHY_IMotionState* motionState)
+{
+ btTransform trans;
+ float tmp[3];
+ motionState->getWorldPosition(tmp[0],tmp[1],tmp[2]);
+ trans.setOrigin(btVector3(tmp[0],tmp[1],tmp[2]));
+
+ btQuaternion orn;
+ motionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]);
+ trans.setRotation(orn);
+ return trans;
+
+}
+
+class BlenderBulletMotionState : public btMotionState
+{
+ PHY_IMotionState* m_blenderMotionState;
+
+public:
+
+ BlenderBulletMotionState(PHY_IMotionState* bms)
+ :m_blenderMotionState(bms)
+ {
+
+ }
+
+ virtual void getWorldTransform(btTransform& worldTrans ) const
+ {
+ float pos[3];
+ float quatOrn[4];
+
+ m_blenderMotionState->getWorldPosition(pos[0],pos[1],pos[2]);
+ m_blenderMotionState->getWorldOrientation(quatOrn[0],quatOrn[1],quatOrn[2],quatOrn[3]);
+ worldTrans.setOrigin(btVector3(pos[0],pos[1],pos[2]));
+ worldTrans.setBasis(btMatrix3x3(btQuaternion(quatOrn[0],quatOrn[1],quatOrn[2],quatOrn[3])));
+ }
+
+ virtual void setWorldTransform(const btTransform& worldTrans)
+ {
+ m_blenderMotionState->setWorldPosition(worldTrans.getOrigin().getX(),worldTrans.getOrigin().getY(),worldTrans.getOrigin().getZ());
+ btQuaternion rotQuat = worldTrans.getRotation();
+ m_blenderMotionState->setWorldOrientation(rotQuat[0],rotQuat[1],rotQuat[2],rotQuat[3]);
+ m_blenderMotionState->calculateWorldTransformations();
+ }
+
+};
+
+
+void CcdPhysicsController::CreateRigidbody()
+{
+
+ btTransform trans = GetTransformFromMotionState(m_MotionState);
+
+ m_bulletMotionState = new BlenderBulletMotionState(m_MotionState);
+
+ m_body = new btRigidBody(m_cci.m_mass,
+ m_bulletMotionState,
+ m_cci.m_collisionShape,
+ m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor,
+ m_cci.m_linearDamping,m_cci.m_angularDamping,
+ m_cci.m_friction,m_cci.m_restitution);
+
+
+
+ //
+ // init the rigidbody properly
+ //
+
+ //setMassProps this also sets collisionFlags
+ //convert collision flags!
+
+ m_body->setCollisionFlags(m_body->getCollisionFlags() | m_cci.m_collisionFlags);
+
+ m_body->setGravity( m_cci.m_gravity);
+ m_body->setDamping(m_cci.m_linearDamping, m_cci.m_angularDamping);
+
+}
+
+CcdPhysicsController::~CcdPhysicsController()
+{
+ //will be reference counted, due to sharing
+ if (m_cci.m_physicsEnv)
+ m_cci.m_physicsEnv->removeCcdPhysicsController(this);
+
+ delete m_MotionState;
+ if (m_bulletMotionState)
+ delete m_bulletMotionState;
+ delete m_body;
+}
+
+ /**
+ SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
+ */
+bool CcdPhysicsController::SynchronizeMotionStates(float time)
+{
+ //sync non-static to motionstate, and static from motionstate (todo: add kinematic etc.)
+
+ if (!m_body->isStaticObject())
+ {
+ const btVector3& worldPos = m_body->getCenterOfMassPosition();
+ m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]);
+
+ const btQuaternion& worldquat = m_body->getOrientation();
+ m_MotionState->setWorldOrientation(worldquat[0],worldquat[1],worldquat[2],worldquat[3]);
+
+ m_MotionState->calculateWorldTransformations();
+
+ float scale[3];
+ m_MotionState->getWorldScaling(scale[0],scale[1],scale[2]);
+ btVector3 scaling(scale[0],scale[1],scale[2]);
+ GetCollisionShape()->setLocalScaling(scaling);
+ } else
+ {
+ btVector3 worldPos;
+ btQuaternion worldquat;
+
+/* m_MotionState->getWorldPosition(worldPos[0],worldPos[1],worldPos[2]);
+ m_MotionState->getWorldOrientation(worldquat[0],worldquat[1],worldquat[2],worldquat[3]);
+ btTransform oldTrans = m_body->getCenterOfMassTransform();
+ btTransform newTrans(worldquat,worldPos);
+
+ m_body->setCenterOfMassTransform(newTrans);
+ //need to keep track of previous position for friction effects...
+
+ m_MotionState->calculateWorldTransformations();
+*/
+ float scale[3];
+ m_MotionState->getWorldScaling(scale[0],scale[1],scale[2]);
+ btVector3 scaling(scale[0],scale[1],scale[2]);
+ GetCollisionShape()->setLocalScaling(scaling);
+ }
+ return true;
+
+}
+
+ /**
+ WriteMotionStateToDynamics synchronizes dynas, kinematic and deformable entities (and do 'late binding')
+ */
+
+void CcdPhysicsController::WriteMotionStateToDynamics(bool nondynaonly)
+{
+
+}
+void CcdPhysicsController::WriteDynamicsToMotionState()
+{
+}
+ // controller replication
+void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl)
+{
+ m_MotionState = motionstate;
+
+
+
+ m_body = 0;
+ CreateRigidbody();
+
+ m_cci.m_physicsEnv->addCcdPhysicsController(this);
+
+
+/* SM_Object* dynaparent=0;
+ SumoPhysicsController* sumoparentctrl = (SumoPhysicsController* )parentctrl;
+
+ if (sumoparentctrl)
+ {
+ dynaparent = sumoparentctrl->GetSumoObject();
+ }
+
+ SM_Object* orgsumoobject = m_sumoObj;
+
+
+ m_sumoObj = new SM_Object(
+ orgsumoobject->getShapeHandle(),
+ orgsumoobject->getMaterialProps(),
+ orgsumoobject->getShapeProps(),
+ dynaparent);
+
+ m_sumoObj->setRigidBody(orgsumoobject->isRigidBody());
+
+ m_sumoObj->setMargin(orgsumoobject->getMargin());
+ m_sumoObj->setPosition(orgsumoobject->getPosition());
+ m_sumoObj->setOrientation(orgsumoobject->getOrientation());
+ //if it is a dyna, register for a callback
+ m_sumoObj->registerCallback(*this);
+
+ m_sumoScene->add(* (m_sumoObj));
+ */
+
+
+
+}
+
+ // kinematic methods
+void CcdPhysicsController::RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local)
+{
+ if (m_body)
+ {
+ m_body->activate(true);
+ if (m_body->isStaticObject())
+ {
+ m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
+ }
+
+
+ btVector3 dloc(dlocX,dlocY,dlocZ);
+ btTransform xform = m_body->getCenterOfMassTransform();
+
+ if (local)
+ {
+ dloc = xform.getBasis()*dloc;
+ }
+
+ xform.setOrigin(xform.getOrigin() + dloc);
+ m_body->setCenterOfMassTransform(xform);
+ }
+
+}
+
+void CcdPhysicsController::RelativeRotate(const float rotval[9],bool local)
+{
+ if (m_body )
+ {
+ m_body->activate(true);
+ if (m_body->isStaticObject())
+ {
+ m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
+ }
+
+ btMatrix3x3 drotmat( rotval[0],rotval[1],rotval[2],
+ rotval[4],rotval[5],rotval[6],
+ rotval[8],rotval[9],rotval[10]);
+
+
+ btMatrix3x3 currentOrn;
+ GetWorldOrientation(currentOrn);
+
+ btTransform xform = m_body->getCenterOfMassTransform();
+
+ xform.setBasis(xform.getBasis()*(local ?
+ drotmat : (currentOrn.inverse() * drotmat * currentOrn)));
+
+ m_body->setCenterOfMassTransform(xform);
+ }
+
+}
+
+void CcdPhysicsController::GetWorldOrientation(btMatrix3x3& mat)
+{
+ float orn[4];
+ m_MotionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]);
+ btQuaternion quat(orn[0],orn[1],orn[2],orn[3]);
+ mat.setRotation(quat);
+}
+
+void CcdPhysicsController::getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal)
+{
+ btQuaternion q = m_body->getCenterOfMassTransform().getRotation();
+ quatImag0 = q[0];
+ quatImag1 = q[1];
+ quatImag2 = q[2];
+ quatReal = q[3];
+}
+void CcdPhysicsController::setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal)
+{
+ m_body->activate(true);
+ if (m_body->isStaticObject())
+ {
+ m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
+ }
+
+ m_MotionState->setWorldOrientation(quatImag0,quatImag1,quatImag2,quatReal);
+ btTransform xform = m_body->getCenterOfMassTransform();
+ xform.setRotation(btQuaternion(quatImag0,quatImag1,quatImag2,quatReal));
+ m_body->setCenterOfMassTransform(xform);
+ m_bulletMotionState->setWorldTransform(xform);
+
+}
+
+void CcdPhysicsController::setPosition(float posX,float posY,float posZ)
+{
+ m_body->activate(true);
+ if (m_body->isStaticObject())
+ {
+ m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
+ }
+
+ m_MotionState->setWorldPosition(posX,posY,posZ);
+ btTransform xform = m_body->getCenterOfMassTransform();
+ xform.setOrigin(btVector3(posX,posY,posZ));
+ m_body->setCenterOfMassTransform(xform);
+ m_bulletMotionState->setWorldTransform(xform);
+
+
+}
+void CcdPhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ)
+{
+}
+
+void CcdPhysicsController::getPosition(PHY__Vector3& pos) const
+{
+ const btTransform& xform = m_body->getCenterOfMassTransform();
+ pos[0] = xform.getOrigin().x();
+ pos[1] = xform.getOrigin().y();
+ pos[2] = xform.getOrigin().z();
+}
+
+void CcdPhysicsController::setScaling(float scaleX,float scaleY,float scaleZ)
+{
+ if (!btFuzzyZero(m_cci.m_scaling.x()-scaleX) ||
+ !btFuzzyZero(m_cci.m_scaling.y()-scaleY) ||
+ !btFuzzyZero(m_cci.m_scaling.z()-scaleZ))
+ {
+ m_cci.m_scaling = btVector3(scaleX,scaleY,scaleZ);
+
+ if (m_body && m_body->getCollisionShape())
+ {
+ m_body->getCollisionShape()->setLocalScaling(m_cci.m_scaling);
+
+ //printf("no inertia recalc for fixed objects with mass=0\n");
+ if (m_cci.m_mass)
+ {
+ m_body->getCollisionShape()->calculateLocalInertia(m_cci.m_mass, m_cci.m_localInertiaTensor);
+ m_body->setMassProps(m_cci.m_mass, m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor);
+ }
+
+ }
+ }
+}
+
+ // physics methods
+void CcdPhysicsController::ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local)
+{
+ btVector3 torque(torqueX,torqueY,torqueZ);
+ btTransform xform = m_body->getCenterOfMassTransform();
+ if (torque.length2() > (SIMD_EPSILON*SIMD_EPSILON))
+ {
+ m_body->activate();
+ }
+ if (local)
+ {
+ torque = xform.getBasis()*torque;
+ }
+ m_body->applyTorque(torque);
+}
+
+void CcdPhysicsController::ApplyForce(float forceX,float forceY,float forceZ,bool local)
+{
+ btVector3 force(forceX,forceY,forceZ);
+
+ if (force.length2() > (SIMD_EPSILON*SIMD_EPSILON))
+ {
+ m_body->activate();
+ }
+
+
+ btTransform xform = m_body->getCenterOfMassTransform();
+ if (local)
+ {
+ force = xform.getBasis()*force;
+ }
+ m_body->applyCentralForce(force);
+}
+void CcdPhysicsController::SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local)
+{
+ btVector3 angvel(ang_velX,ang_velY,ang_velZ);
+ if (angvel.length2() > (SIMD_EPSILON*SIMD_EPSILON))
+ {
+ m_body->activate(true);
+ }
+
+ {
+ btTransform xform = m_body->getCenterOfMassTransform();
+ if (local)
+ {
+ angvel = xform.getBasis()*angvel;
+ }
+
+ m_body->setAngularVelocity(angvel);
+ }
+
+}
+void CcdPhysicsController::SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local)
+{
+
+ btVector3 linVel(lin_velX,lin_velY,lin_velZ);
+ if (linVel.length2() > (SIMD_EPSILON*SIMD_EPSILON))
+ {
+ m_body->activate(true);
+ }
+
+ {
+ btTransform xform = m_body->getCenterOfMassTransform();
+ if (local)
+ {
+ linVel = xform.getBasis()*linVel;
+ }
+ m_body->setLinearVelocity(linVel);
+ }
+}
+void CcdPhysicsController::applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ)
+{
+ btVector3 impulse(impulseX,impulseY,impulseZ);
+
+ if (impulse.length2() > (SIMD_EPSILON*SIMD_EPSILON))
+ {
+ m_body->activate();
+
+ btVector3 pos(attachX,attachY,attachZ);
+
+ m_body->activate();
+
+ m_body->applyImpulse(impulse,pos);
+ }
+
+}
+void CcdPhysicsController::SetActive(bool active)
+{
+}
+ // reading out information from physics
+void CcdPhysicsController::GetLinearVelocity(float& linvX,float& linvY,float& linvZ)
+{
+ const btVector3& linvel = this->m_body->getLinearVelocity();
+ linvX = linvel.x();
+ linvY = linvel.y();
+ linvZ = linvel.z();
+
+}
+
+void CcdPhysicsController::GetAngularVelocity(float& angVelX,float& angVelY,float& angVelZ)
+{
+ const btVector3& angvel= m_body->getAngularVelocity();
+ angVelX = angvel.x();
+ angVelY = angvel.y();
+ angVelZ = angvel.z();
+}
+
+void CcdPhysicsController::GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ)
+{
+ btVector3 pos(posX,posY,posZ);
+ btVector3 rel_pos = pos-m_body->getCenterOfMassPosition();
+ btVector3 linvel = m_body->getVelocityInLocalPoint(rel_pos);
+ linvX = linvel.x();
+ linvY = linvel.y();
+ linvZ = linvel.z();
+}
+void CcdPhysicsController::getReactionForce(float& forceX,float& forceY,float& forceZ)
+{
+}
+
+ // dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted
+void CcdPhysicsController::setRigidBody(bool rigid)
+{
+ if (!rigid)
+ {
+ //fake it for now
+ btVector3 inertia = m_body->getInvInertiaDiagLocal();
+ inertia[1] = 0.f;
+ m_body->setInvInertiaDiagLocal(inertia);
+ m_body->updateInertiaTensor();
+ }
+}
+
+ // clientinfo for raycasts for example
+void* CcdPhysicsController::getNewClientInfo()
+{
+ return m_newClientInfo;
+}
+void CcdPhysicsController::setNewClientInfo(void* clientinfo)
+{
+ m_newClientInfo = clientinfo;
+}
+
+
+void CcdPhysicsController::UpdateDeactivation(float timeStep)
+{
+ m_body->updateDeactivation( timeStep);
+}
+
+bool CcdPhysicsController::wantsSleeping()
+{
+
+ return m_body->wantsSleeping();
+}
+
+PHY_IPhysicsController* CcdPhysicsController::GetReplica()
+{
+ //very experimental, shape sharing is not implemented yet.
+ //just support btSphereShape/ConeShape for now
+
+ CcdConstructionInfo cinfo = m_cci;
+ if (cinfo.m_collisionShape)
+ {
+ switch (cinfo.m_collisionShape->getShapeType())
+ {
+ case SPHERE_SHAPE_PROXYTYPE:
+ {
+ btSphereShape* orgShape = (btSphereShape*)cinfo.m_collisionShape;
+ cinfo.m_collisionShape = new btSphereShape(*orgShape);
+ break;
+ }
+
+ case CONE_SHAPE_PROXYTYPE:
+ {
+ btConeShape* orgShape = (btConeShape*)cinfo.m_collisionShape;
+ cinfo.m_collisionShape = new btConeShape(*orgShape);
+ break;
+ }
+
+
+ default:
+ {
+ return 0;
+ }
+ }
+ }
+
+ cinfo.m_MotionState = new DefaultMotionState();
+
+ CcdPhysicsController* replica = new CcdPhysicsController(cinfo);
+ return replica;
+}
+
+///////////////////////////////////////////////////////////
+///A small utility class, DefaultMotionState
+///
+///////////////////////////////////////////////////////////
+
+DefaultMotionState::DefaultMotionState()
+{
+ m_worldTransform.setIdentity();
+ m_localScaling.setValue(1.f,1.f,1.f);
+}
+
+
+DefaultMotionState::~DefaultMotionState()
+{
+
+}
+
+void DefaultMotionState::getWorldPosition(float& posX,float& posY,float& posZ)
+{
+ posX = m_worldTransform.getOrigin().x();
+ posY = m_worldTransform.getOrigin().y();
+ posZ = m_worldTransform.getOrigin().z();
+}
+
+void DefaultMotionState::getWorldScaling(float& scaleX,float& scaleY,float& scaleZ)
+{
+ scaleX = m_localScaling.getX();
+ scaleY = m_localScaling.getY();
+ scaleZ = m_localScaling.getZ();
+}
+
+void DefaultMotionState::getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal)
+{
+ quatIma0 = m_worldTransform.getRotation().x();
+ quatIma1 = m_worldTransform.getRotation().y();
+ quatIma2 = m_worldTransform.getRotation().z();
+ quatReal = m_worldTransform.getRotation()[3];
+}
+
+void DefaultMotionState::setWorldPosition(float posX,float posY,float posZ)
+{
+ btPoint3 pos(posX,posY,posZ);
+ m_worldTransform.setOrigin( pos );
+}
+
+void DefaultMotionState::setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal)
+{
+ btQuaternion orn(quatIma0,quatIma1,quatIma2,quatReal);
+ m_worldTransform.setRotation( orn );
+}
+
+void DefaultMotionState::calculateWorldTransformations()
+{
+
+}
+
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
new file mode 100644
index 00000000000..11fef56401f
--- /dev/null
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
@@ -0,0 +1,248 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+#ifndef BULLET2_PHYSICSCONTROLLER_H
+#define BULLET2_PHYSICSCONTROLLER_H
+
+#include "PHY_IPhysicsController.h"
+
+/// PHY_IPhysicsController is the abstract simplified Interface to a physical object.
+/// It contains the IMotionState and IDeformableMesh Interfaces.
+#include "btBulletDynamicsCommon.h"
+
+#include "PHY_IMotionState.h"
+
+extern float gDeactivationTime;
+extern float gLinearSleepingTreshold;
+extern float gAngularSleepingTreshold;
+extern bool gDisableDeactivation;
+class CcdPhysicsEnvironment;
+class btMotionState;
+
+
+
+struct CcdConstructionInfo
+{
+
+ ///CollisionFilterGroups provides some optional usage of basic collision filtering
+ ///this is done during broadphase, so very early in the pipeline
+ ///more advanced collision filtering should be done in btCollisionDispatcher::NeedsCollision
+ enum CollisionFilterGroups
+ {
+ DefaultFilter = 1,
+ StaticFilter = 2,
+ KinematicFilter = 4,
+ DebrisFilter = 8,
+ AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter,
+ };
+
+
+ CcdConstructionInfo()
+ : m_gravity(0,0,0),
+ m_scaling(1.f,1.f,1.f),
+ m_mass(0.f),
+ m_restitution(0.1f),
+ m_friction(0.5f),
+ m_linearDamping(0.1f),
+ m_angularDamping(0.1f),
+ m_collisionFlags(0),
+ m_collisionFilterGroup(DefaultFilter),
+ m_collisionFilterMask(AllFilter),
+ m_MotionState(0),
+ m_physicsEnv(0),
+ m_inertiaFactor(1.f)
+ {
+ }
+
+ btVector3 m_localInertiaTensor;
+ btVector3 m_gravity;
+ btVector3 m_scaling;
+ btScalar m_mass;
+ btScalar m_restitution;
+ btScalar m_friction;
+ btScalar m_linearDamping;
+ btScalar m_angularDamping;
+ int m_collisionFlags;
+
+ ///optional use of collision group/mask:
+ ///only collision with object goups that match the collision mask.
+ ///this is very basic early out. advanced collision filtering should be
+ ///done in the btCollisionDispatcher::NeedsCollision and NeedsResponse
+ ///both values default to 1
+ short int m_collisionFilterGroup;
+ short int m_collisionFilterMask;
+
+
+ btCollisionShape* m_collisionShape;
+ class PHY_IMotionState* m_MotionState;
+
+ CcdPhysicsEnvironment* m_physicsEnv; //needed for self-replication
+ float m_inertiaFactor;//tweak the inertia (hooked up to Blender 'formfactor'
+};
+
+
+class btRigidBody;
+
+///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution.
+class CcdPhysicsController : public PHY_IPhysicsController
+{
+ btRigidBody* m_body;
+ class PHY_IMotionState* m_MotionState;
+ btMotionState* m_bulletMotionState;
+
+
+ void* m_newClientInfo;
+
+ CcdConstructionInfo m_cci;//needed for replication
+ void GetWorldOrientation(btMatrix3x3& mat);
+
+ void CreateRigidbody();
+
+ public:
+
+ int m_collisionDelay;
+
+
+ CcdPhysicsController (const CcdConstructionInfo& ci);
+
+ virtual ~CcdPhysicsController();
+
+
+ btRigidBody* GetRigidBody() { return m_body;}
+
+ btCollisionShape* GetCollisionShape() {
+ return m_body->getCollisionShape();
+ }
+ ////////////////////////////////////
+ // PHY_IPhysicsController interface
+ ////////////////////////////////////
+
+
+ /**
+ SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
+ */
+ virtual bool SynchronizeMotionStates(float time);
+ /**
+ WriteMotionStateToDynamics ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
+ */
+
+ virtual void WriteMotionStateToDynamics(bool nondynaonly);
+ virtual void WriteDynamicsToMotionState();
+ // controller replication
+ virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl);
+
+ // kinematic methods
+ virtual void RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local);
+ virtual void RelativeRotate(const float drot[9],bool local);
+ virtual void getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal);
+ virtual void setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal);
+ virtual void setPosition(float posX,float posY,float posZ);
+ virtual void getPosition(PHY__Vector3& pos) const;
+
+ virtual void setScaling(float scaleX,float scaleY,float scaleZ);
+
+ // physics methods
+ virtual void ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local);
+ virtual void ApplyForce(float forceX,float forceY,float forceZ,bool local);
+ virtual void SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local);
+ virtual void SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local);
+ virtual void applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ);
+ virtual void SetActive(bool active);
+
+ // reading out information from physics
+ virtual void GetLinearVelocity(float& linvX,float& linvY,float& linvZ);
+ virtual void GetAngularVelocity(float& angVelX,float& angVelY,float& angVelZ);
+ virtual void GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ);
+ virtual void getReactionForce(float& forceX,float& forceY,float& forceZ);
+
+ // dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted
+ virtual void setRigidBody(bool rigid);
+
+
+ virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ);
+
+ // clientinfo for raycasts for example
+ virtual void* getNewClientInfo();
+ virtual void setNewClientInfo(void* clientinfo);
+ virtual PHY_IPhysicsController* GetReplica();
+
+ ///There should be no 'SetCollisionFilterGroup' method, as changing this during run-time is will result in errors
+ short int GetCollisionFilterGroup() const
+ {
+ return m_cci.m_collisionFilterGroup;
+ }
+ ///There should be no 'SetCollisionFilterGroup' method, as changing this during run-time is will result in errors
+ short int GetCollisionFilterMask() const
+ {
+ return m_cci.m_collisionFilterMask;
+ }
+
+
+ virtual void calcXform() {} ;
+ virtual void SetMargin(float margin) {};
+ virtual float GetMargin() const {return 0.f;};
+
+
+ bool wantsSleeping();
+
+ void UpdateDeactivation(float timeStep);
+
+ static btTransform GetTransformFromMotionState(PHY_IMotionState* motionState);
+
+ void setAabb(const btVector3& aabbMin,const btVector3& aabbMax);
+
+
+ class PHY_IMotionState* GetMotionState()
+ {
+ return m_MotionState;
+ }
+
+ const class PHY_IMotionState* GetMotionState() const
+ {
+ return m_MotionState;
+ }
+
+
+};
+
+
+
+
+///DefaultMotionState implements standard motionstate, using btTransform
+class DefaultMotionState : public PHY_IMotionState
+
+{
+ public:
+ DefaultMotionState();
+
+ virtual ~DefaultMotionState();
+
+ virtual void getWorldPosition(float& posX,float& posY,float& posZ);
+ virtual void getWorldScaling(float& scaleX,float& scaleY,float& scaleZ);
+ virtual void getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal);
+
+ virtual void setWorldPosition(float posX,float posY,float posZ);
+ virtual void setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal);
+
+ virtual void calculateWorldTransformations();
+
+ btTransform m_worldTransform;
+ btVector3 m_localScaling;
+
+};
+
+
+#endif //BULLET2_PHYSICSCONTROLLER_H
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
new file mode 100644
index 00000000000..99c3e5f77c7
--- /dev/null
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
@@ -0,0 +1,1307 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+
+
+#include "CcdPhysicsEnvironment.h"
+#include "CcdPhysicsController.h"
+
+#include <algorithm>
+#include "btBulletDynamicsCommon.h"
+#include "LinearMath/btIDebugDraw.h"
+#include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h"
+
+//profiling/timings
+#include "LinearMath/btQuickprof.h"
+
+
+#include "PHY_IMotionState.h"
+
+
+bool useIslands = true;
+
+#ifdef NEW_BULLET_VEHICLE_SUPPORT
+#include "BulletDynamics/Vehicle/btRaycastVehicle.h"
+#include "BulletDynamics/Vehicle/btVehicleRaycaster.h"
+#include "BulletDynamics/Vehicle/btWheelInfo.h"
+#include "PHY_IVehicle.h"
+btRaycastVehicle::btVehicleTuning gTuning;
+
+#endif //NEW_BULLET_VEHICLE_SUPPORT
+#include "LinearMath/btAabbUtil2.h"
+
+
+#ifdef WIN32
+void DrawRasterizerLine(const float* from,const float* to,int color);
+#endif
+
+
+#include "BulletDynamics/ConstraintSolver/btContactConstraint.h"
+
+
+#include <stdio.h>
+
+#ifdef NEW_BULLET_VEHICLE_SUPPORT
+class WrapperVehicle : public PHY_IVehicle
+{
+
+ btRaycastVehicle* m_vehicle;
+ PHY_IPhysicsController* m_chassis;
+
+public:
+
+ WrapperVehicle(btRaycastVehicle* vehicle,PHY_IPhysicsController* chassis)
+ :m_vehicle(vehicle),
+ m_chassis(chassis)
+ {
+ }
+
+ btRaycastVehicle* GetVehicle()
+ {
+ return m_vehicle;
+ }
+
+ PHY_IPhysicsController* GetChassis()
+ {
+ return m_chassis;
+ }
+
+ virtual void AddWheel(
+ PHY_IMotionState* motionState,
+ PHY__Vector3 connectionPoint,
+ PHY__Vector3 downDirection,
+ PHY__Vector3 axleDirection,
+ float suspensionRestLength,
+ float wheelRadius,
+ bool hasSteering
+ )
+ {
+ btVector3 connectionPointCS0(connectionPoint[0],connectionPoint[1],connectionPoint[2]);
+ btVector3 wheelDirectionCS0(downDirection[0],downDirection[1],downDirection[2]);
+ btVector3 wheelAxle(axleDirection[0],axleDirection[1],axleDirection[2]);
+
+
+ btWheelInfo& info = m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxle,
+ suspensionRestLength,wheelRadius,gTuning,hasSteering);
+ info.m_clientInfo = motionState;
+
+ }
+
+ void SyncWheels()
+ {
+ int numWheels = GetNumWheels();
+ int i;
+ for (i=0;i<numWheels;i++)
+ {
+ btWheelInfo& info = m_vehicle->getWheelInfo(i);
+ PHY_IMotionState* motionState = (PHY_IMotionState*)info.m_clientInfo ;
+ // m_vehicle->updateWheelTransformsWS(info,false);
+ m_vehicle->updateWheelTransform(i,false);
+ btTransform trans = m_vehicle->getWheelInfo(i).m_worldTransform;
+ btQuaternion orn = trans.getRotation();
+ const btVector3& pos = trans.getOrigin();
+ motionState->setWorldOrientation(orn.x(),orn.y(),orn.z(),orn[3]);
+ motionState->setWorldPosition(pos.x(),pos.y(),pos.z());
+
+ }
+ }
+
+ virtual int GetNumWheels() const
+ {
+ return m_vehicle->getNumWheels();
+ }
+
+ virtual void GetWheelPosition(int wheelIndex,float& posX,float& posY,float& posZ) const
+ {
+ btTransform trans = m_vehicle->getWheelTransformWS(wheelIndex);
+ posX = trans.getOrigin().x();
+ posY = trans.getOrigin().y();
+ posZ = trans.getOrigin().z();
+ }
+ virtual void GetWheelOrientationQuaternion(int wheelIndex,float& quatX,float& quatY,float& quatZ,float& quatW) const
+ {
+ btTransform trans = m_vehicle->getWheelTransformWS(wheelIndex);
+ btQuaternion quat = trans.getRotation();
+ btMatrix3x3 orn2(quat);
+
+ quatX = trans.getRotation().x();
+ quatY = trans.getRotation().y();
+ quatZ = trans.getRotation().z();
+ quatW = trans.getRotation()[3];
+
+
+ //printf("test");
+
+
+ }
+
+ virtual float GetWheelRotation(int wheelIndex) const
+ {
+ float rotation = 0.f;
+
+ if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels()))
+ {
+ btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex);
+ rotation = info.m_rotation;
+ }
+ return rotation;
+
+ }
+
+
+
+ virtual int GetUserConstraintId() const
+ {
+ return m_vehicle->getUserConstraintId();
+ }
+
+ virtual int GetUserConstraintType() const
+ {
+ return m_vehicle->getUserConstraintType();
+ }
+
+ virtual void SetSteeringValue(float steering,int wheelIndex)
+ {
+ m_vehicle->setSteeringValue(steering,wheelIndex);
+ }
+
+ virtual void ApplyEngineForce(float force,int wheelIndex)
+ {
+ m_vehicle->applyEngineForce(force,wheelIndex);
+ }
+
+ virtual void ApplyBraking(float braking,int wheelIndex)
+ {
+ if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels()))
+ {
+ btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex);
+ info.m_brake = braking;
+ }
+ }
+
+ virtual void SetWheelFriction(float friction,int wheelIndex)
+ {
+ if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels()))
+ {
+ btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex);
+ info.m_frictionSlip = friction;
+ }
+
+ }
+
+ virtual void SetSuspensionStiffness(float suspensionStiffness,int wheelIndex)
+ {
+ if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels()))
+ {
+ btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex);
+ info.m_suspensionStiffness = suspensionStiffness;
+
+ }
+ }
+
+ virtual void SetSuspensionDamping(float suspensionDamping,int wheelIndex)
+ {
+ if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels()))
+ {
+ btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex);
+ info.m_wheelsDampingRelaxation = suspensionDamping;
+ }
+ }
+
+ virtual void SetSuspensionCompression(float suspensionCompression,int wheelIndex)
+ {
+ if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels()))
+ {
+ btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex);
+ info.m_wheelsDampingCompression = suspensionCompression;
+ }
+ }
+
+
+
+ virtual void SetRollInfluence(float rollInfluence,int wheelIndex)
+ {
+ if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels()))
+ {
+ btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex);
+ info.m_rollInfluence = rollInfluence;
+ }
+ }
+
+ virtual void SetCoordinateSystem(int rightIndex,int upIndex,int forwardIndex)
+ {
+ m_vehicle->setCoordinateSystem(rightIndex,upIndex,forwardIndex);
+ }
+
+
+
+};
+#endif //NEW_BULLET_VEHICLE_SUPPORT
+
+
+void CcdPhysicsEnvironment::setDebugDrawer(btIDebugDraw* debugDrawer)
+{
+ if (debugDrawer && m_dynamicsWorld)
+ m_dynamicsWorld->setDebugDrawer(debugDrawer);
+ m_debugDrawer = debugDrawer;
+}
+
+static void DrawAabb(btIDebugDraw* debugDrawer,const btVector3& from,const btVector3& to,const btVector3& color)
+{
+ btVector3 halfExtents = (to-from)* 0.5f;
+ btVector3 center = (to+from) *0.5f;
+ int i,j;
+
+ btVector3 edgecoord(1.f,1.f,1.f),pa,pb;
+ for (i=0;i<4;i++)
+ {
+ for (j=0;j<3;j++)
+ {
+ pa = btVector3(edgecoord[0]*halfExtents[0], edgecoord[1]*halfExtents[1],
+ edgecoord[2]*halfExtents[2]);
+ pa+=center;
+
+ int othercoord = j%3;
+ edgecoord[othercoord]*=-1.f;
+ pb = btVector3(edgecoord[0]*halfExtents[0], edgecoord[1]*halfExtents[1],
+ edgecoord[2]*halfExtents[2]);
+ pb+=center;
+
+ debugDrawer->drawLine(pa,pb,color);
+ }
+ edgecoord = btVector3(-1.f,-1.f,-1.f);
+ if (i<3)
+ edgecoord[i]*=-1.f;
+ }
+
+
+}
+
+
+
+
+
+
+CcdPhysicsEnvironment::CcdPhysicsEnvironment(btDispatcher* dispatcher,btOverlappingPairCache* pairCache)
+:m_scalingPropagated(false),
+m_numIterations(10),
+m_numTimeSubSteps(1),
+m_ccdMode(0),
+m_solverType(-1),
+m_profileTimings(0),
+m_enableSatCollisionDetection(false)
+{
+
+ for (int i=0;i<PHY_NUM_RESPONSE;i++)
+ {
+ m_triggerCallbacks[i] = 0;
+ }
+ if (!dispatcher)
+ dispatcher = new btCollisionDispatcher();
+
+
+ if(!pairCache)
+ {
+
+ //todo: calculate/let user specify this world sizes
+ btVector3 worldMin(-10000,-10000,-10000);
+ btVector3 worldMax(10000,10000,10000);
+
+ pairCache = new btAxisSweep3(worldMin,worldMax);
+
+ //broadphase = new btSimpleBroadphase();
+ }
+
+
+ setSolverType(1);//issues with quickstep and memory allocations
+
+ m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,pairCache,new btSequentialImpulseConstraintSolver());
+ m_debugDrawer = 0;
+ m_gravity = btVector3(0.f,-10.f,0.f);
+ m_dynamicsWorld->setGravity(m_gravity);
+
+
+}
+
+void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl)
+{
+ btRigidBody* body = ctrl->GetRigidBody();
+
+ //this m_userPointer is just used for triggers, see CallbackTriggers
+ body->setUserPointer(ctrl);
+
+ body->setGravity( m_gravity );
+ m_controllers.push_back(ctrl);
+
+ m_dynamicsWorld->addRigidBody(body);
+ if (body->isStaticOrKinematicObject())
+ {
+ body->setActivationState(ISLAND_SLEEPING);
+ }
+
+
+ //CollisionObject(body,ctrl->GetCollisionFilterGroup(),ctrl->GetCollisionFilterMask());
+
+ assert(body->getBroadphaseHandle());
+
+ btBroadphaseInterface* scene = getBroadphase();
+
+
+ btCollisionShape* shapeinterface = ctrl->GetCollisionShape();
+
+ assert(shapeinterface);
+
+ const btTransform& t = ctrl->GetRigidBody()->getCenterOfMassTransform();
+
+
+ btPoint3 minAabb,maxAabb;
+
+ shapeinterface->getAabb(t,minAabb,maxAabb);
+
+ float timeStep = 0.02f;
+
+
+ //extent it with the motion
+
+ btVector3 linMotion = body->getLinearVelocity()*timeStep;
+
+ float maxAabbx = maxAabb.getX();
+ float maxAabby = maxAabb.getY();
+ float maxAabbz = maxAabb.getZ();
+ float minAabbx = minAabb.getX();
+ float minAabby = minAabb.getY();
+ float minAabbz = minAabb.getZ();
+
+ if (linMotion.x() > 0.f)
+ maxAabbx += linMotion.x();
+ else
+ minAabbx += linMotion.x();
+ if (linMotion.y() > 0.f)
+ maxAabby += linMotion.y();
+ else
+ minAabby += linMotion.y();
+ if (linMotion.z() > 0.f)
+ maxAabbz += linMotion.z();
+ else
+ minAabbz += linMotion.z();
+
+
+ minAabb = btVector3(minAabbx,minAabby,minAabbz);
+ maxAabb = btVector3(maxAabbx,maxAabby,maxAabbz);
+
+
+
+
+}
+
+void CcdPhysicsEnvironment::removeCcdPhysicsController(CcdPhysicsController* ctrl)
+{
+
+ //also remove constraint
+
+
+
+ m_dynamicsWorld->removeRigidBody(ctrl->GetRigidBody());
+
+
+ {
+ std::vector<CcdPhysicsController*>::iterator i =
+ std::find(m_controllers.begin(), m_controllers.end(), ctrl);
+ if (!(i == m_controllers.end()))
+ {
+ std::swap(*i, m_controllers.back());
+ m_controllers.pop_back();
+ }
+ }
+
+ //remove it from the triggers
+ {
+ std::vector<CcdPhysicsController*>::iterator i =
+ std::find(m_triggerControllers.begin(), m_triggerControllers.end(), ctrl);
+ if (!(i == m_triggerControllers.end()))
+ {
+ std::swap(*i, m_triggerControllers.back());
+ m_triggerControllers.pop_back();
+ }
+ }
+
+
+}
+
+
+void CcdPhysicsEnvironment::beginFrame()
+{
+
+}
+
+
+bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep)
+{
+
+ int i,numCtrl = GetNumControllers();
+ for (i=0;i<numCtrl;i++)
+ {
+ CcdPhysicsController* ctrl = GetPhysicsController(i);
+ ctrl->SynchronizeMotionStates(timeStep);
+ }
+
+ float subStep = timeStep / float(m_numTimeSubSteps);
+ for (i=0;i<m_numTimeSubSteps;i++)
+ {
+ m_dynamicsWorld->stepSimulation(subStep,0);//perform always a full simulation step
+ }
+
+ numCtrl = GetNumControllers();
+ for (i=0;i<numCtrl;i++)
+ {
+ CcdPhysicsController* ctrl = GetPhysicsController(i);
+ ctrl->SynchronizeMotionStates(timeStep);
+ }
+
+ for (i=0;i<m_wrapperVehicles.size();i++)
+ {
+ WrapperVehicle* veh = m_wrapperVehicles[i];
+ veh->SyncWheels();
+ }
+
+ CallbackTriggers();
+
+ return true;
+}
+
+
+void CcdPhysicsEnvironment::setDebugMode(int debugMode)
+{
+ if (m_debugDrawer){
+ m_debugDrawer->setDebugMode(debugMode);
+ }
+}
+
+void CcdPhysicsEnvironment::setNumIterations(int numIter)
+{
+ m_numIterations = numIter;
+}
+void CcdPhysicsEnvironment::setDeactivationTime(float dTime)
+{
+ gDeactivationTime = dTime;
+}
+void CcdPhysicsEnvironment::setDeactivationLinearTreshold(float linTresh)
+{
+ gLinearSleepingTreshold = linTresh;
+}
+void CcdPhysicsEnvironment::setDeactivationAngularTreshold(float angTresh)
+{
+ gAngularSleepingTreshold = angTresh;
+}
+
+void CcdPhysicsEnvironment::setContactBreakingTreshold(float contactBreakingTreshold)
+{
+ gContactBreakingThreshold = contactBreakingTreshold;
+
+}
+
+
+void CcdPhysicsEnvironment::setCcdMode(int ccdMode)
+{
+ m_ccdMode = ccdMode;
+}
+
+
+void CcdPhysicsEnvironment::setSolverSorConstant(float sor)
+{
+ m_solverInfo.m_sor = sor;
+}
+
+void CcdPhysicsEnvironment::setSolverTau(float tau)
+{
+ m_solverInfo.m_tau = tau;
+}
+void CcdPhysicsEnvironment::setSolverDamping(float damping)
+{
+ m_solverInfo.m_damping = damping;
+}
+
+
+void CcdPhysicsEnvironment::setLinearAirDamping(float damping)
+{
+ gLinearAirDamping = damping;
+}
+
+void CcdPhysicsEnvironment::setUseEpa(bool epa)
+{
+ //gUseEpa = epa;
+}
+
+void CcdPhysicsEnvironment::setSolverType(int solverType)
+{
+
+ switch (solverType)
+ {
+ case 1:
+ {
+ if (m_solverType != solverType)
+ {
+
+ m_solver = new btSequentialImpulseConstraintSolver();
+
+ break;
+ }
+ }
+
+ case 0:
+ default:
+ if (m_solverType != solverType)
+ {
+// m_solver = new OdeConstraintSolver();
+
+ break;
+ }
+
+ };
+
+ m_solverType = solverType ;
+}
+
+
+
+
+
+
+void CcdPhysicsEnvironment::setGravity(float x,float y,float z)
+{
+ m_gravity = btVector3(x,y,z);
+ m_dynamicsWorld->setGravity(m_gravity);
+
+}
+
+
+
+
+static int gConstraintUid = 1;
+
+//Following the COLLADA physics specification for constraints
+int CcdPhysicsEnvironment::createUniversalD6Constraint(
+ class PHY_IPhysicsController* ctrlRef,class PHY_IPhysicsController* ctrlOther,
+ btTransform& frameInA,
+ btTransform& frameInB,
+ const btVector3& linearMinLimits,
+ const btVector3& linearMaxLimits,
+ const btVector3& angularMinLimits,
+ const btVector3& angularMaxLimits
+)
+{
+
+ //we could either add some logic to recognize ball-socket and hinge, or let that up to the user
+ //perhaps some warning or hint that hinge/ball-socket is more efficient?
+
+ btGeneric6DofConstraint* genericConstraint = 0;
+ CcdPhysicsController* ctrl0 = (CcdPhysicsController*) ctrlRef;
+ CcdPhysicsController* ctrl1 = (CcdPhysicsController*) ctrlOther;
+
+ btRigidBody* rb0 = ctrl0->GetRigidBody();
+ btRigidBody* rb1 = ctrl1->GetRigidBody();
+
+ if (rb1)
+ {
+
+
+ genericConstraint = new btGeneric6DofConstraint(
+ *rb0,*rb1,
+ frameInA,frameInB);
+ genericConstraint->setLinearLowerLimit(linearMinLimits);
+ genericConstraint->setLinearUpperLimit(linearMaxLimits);
+ genericConstraint->setAngularLowerLimit(angularMinLimits);
+ genericConstraint->setAngularUpperLimit(angularMaxLimits);
+ } else
+ {
+ // TODO: Implement single body case...
+ //No, we can use a fixed rigidbody in above code, rather then unnecessary duplation of code
+
+ }
+
+ if (genericConstraint)
+ {
+ // m_constraints.push_back(genericConstraint);
+ m_dynamicsWorld->addConstraint(genericConstraint);
+
+ genericConstraint->setUserConstraintId(gConstraintUid++);
+ genericConstraint->setUserConstraintType(PHY_GENERIC_6DOF_CONSTRAINT);
+ //64 bit systems can't cast pointer to int. could use size_t instead.
+ return genericConstraint->getUserConstraintId();
+ }
+ return 0;
+}
+
+
+
+void CcdPhysicsEnvironment::removeConstraint(int constraintId)
+{
+
+ int i;
+ int numConstraints = m_dynamicsWorld->getNumConstraints();
+ for (i=0;i<numConstraints;i++)
+ {
+ btTypedConstraint* constraint = m_dynamicsWorld->getConstraint(i);
+ if (constraint->getUserConstraintId() == constraintId)
+ {
+ constraint->getRigidBodyA().activate();
+ constraint->getRigidBodyB().activate();
+ m_dynamicsWorld->removeConstraint(constraint);
+ break;
+ }
+ }
+}
+
+
+struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
+{
+ PHY_IPhysicsController* m_ignoreClient;
+
+ FilterClosestRayResultCallback (PHY_IPhysicsController* ignoreClient,const btVector3& rayFrom,const btVector3& rayTo)
+ : btCollisionWorld::ClosestRayResultCallback(rayFrom,rayTo),
+ m_ignoreClient(ignoreClient)
+ {
+
+ }
+
+ virtual ~FilterClosestRayResultCallback()
+ {
+ }
+
+ virtual float AddSingleResult( btCollisionWorld::LocalRayResult& rayResult)
+ {
+ CcdPhysicsController* curHit = static_cast<CcdPhysicsController*>(rayResult.m_collisionObject->getUserPointer());
+ //ignore client...
+ if (curHit != m_ignoreClient)
+ {
+ //if valid
+ return ClosestRayResultCallback::AddSingleResult(rayResult);
+ }
+ return m_closestHitFraction;
+ }
+
+};
+
+PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ,
+ float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ)
+{
+
+
+ float minFraction = 1.f;
+
+ btVector3 rayFrom(fromX,fromY,fromZ);
+ btVector3 rayTo(toX,toY,toZ);
+
+ btVector3 hitPointWorld,normalWorld;
+
+ //Either Ray Cast with or without filtering
+
+ //btCollisionWorld::ClosestRayResultCallback rayCallback(rayFrom,rayTo);
+ FilterClosestRayResultCallback rayCallback(ignoreClient,rayFrom,rayTo);
+
+
+ PHY_IPhysicsController* nearestHit = 0;
+
+ m_dynamicsWorld->rayTest(rayFrom,rayTo,rayCallback);
+ if (rayCallback.HasHit())
+ {
+ nearestHit = static_cast<CcdPhysicsController*>(rayCallback.m_collisionObject->getUserPointer());
+ hitX = rayCallback.m_hitPointWorld.getX();
+ hitY = rayCallback.m_hitPointWorld.getY();
+ hitZ = rayCallback.m_hitPointWorld.getZ();
+
+ if (rayCallback.m_hitNormalWorld.length2() > (SIMD_EPSILON*SIMD_EPSILON))
+ {
+ rayCallback.m_hitNormalWorld.normalize();
+ } else
+ {
+ rayCallback.m_hitNormalWorld.setValue(1,0,0);
+ }
+ normalX = rayCallback.m_hitNormalWorld.getX();
+ normalY = rayCallback.m_hitNormalWorld.getY();
+ normalZ = rayCallback.m_hitNormalWorld.getZ();
+
+ }
+
+
+ return nearestHit;
+}
+
+
+
+int CcdPhysicsEnvironment::getNumContactPoints()
+{
+ return 0;
+}
+
+void CcdPhysicsEnvironment::getContactPoint(int i,float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ)
+{
+
+}
+
+
+
+
+btBroadphaseInterface* CcdPhysicsEnvironment::getBroadphase()
+{
+ return m_dynamicsWorld->getBroadphase();
+}
+
+
+
+
+CcdPhysicsEnvironment::~CcdPhysicsEnvironment()
+{
+
+#ifdef NEW_BULLET_VEHICLE_SUPPORT
+ m_wrapperVehicles.clear();
+#endif //NEW_BULLET_VEHICLE_SUPPORT
+
+ //m_broadphase->DestroyScene();
+ //delete broadphase ? release reference on broadphase ?
+
+ //first delete scene, then dispatcher, because pairs have to release manifolds on the dispatcher
+ //delete m_dispatcher;
+ delete m_dynamicsWorld;
+
+
+
+}
+
+
+int CcdPhysicsEnvironment::GetNumControllers()
+{
+ return m_controllers.size();
+}
+
+
+CcdPhysicsController* CcdPhysicsEnvironment::GetPhysicsController( int index)
+{
+ return m_controllers[index];
+}
+
+
+
+
+void CcdPhysicsEnvironment::setConstraintParam(int constraintId,int param,float value0,float value1)
+{
+ btTypedConstraint* typedConstraint = getConstraintById(constraintId);
+ switch (typedConstraint->getUserConstraintType())
+ {
+ case PHY_GENERIC_6DOF_CONSTRAINT:
+ {
+ //param = 1..12, min0,max0,min1,max1...min6,max6
+ btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint;
+ genCons->SetLimit(param,value0,value1);
+ break;
+ };
+ default:
+ {
+ };
+ };
+}
+
+btTypedConstraint* CcdPhysicsEnvironment::getConstraintById(int constraintId)
+{
+
+ int numConstraints = m_dynamicsWorld->getNumConstraints();
+ int i;
+ for (i=0;i<numConstraints;i++)
+ {
+ btTypedConstraint* constraint = m_dynamicsWorld->getConstraint(i);
+ if (constraint->getUserConstraintId()==constraintId)
+ {
+ return constraint;
+ }
+ }
+ return 0;
+}
+
+
+void CcdPhysicsEnvironment::addSensor(PHY_IPhysicsController* ctrl)
+{
+
+ CcdPhysicsController* ctrl1 = (CcdPhysicsController* )ctrl;
+ std::vector<CcdPhysicsController*>::iterator i =
+ std::find(m_controllers.begin(), m_controllers.end(), ctrl);
+ if ((i == m_controllers.end()))
+ {
+ addCcdPhysicsController(ctrl1);
+ }
+ //force collision detection with everything, including static objects (might hurt performance!)
+ ctrl1->GetRigidBody()->getBroadphaseHandle()->m_collisionFilterMask = btBroadphaseProxy::AllFilter;
+ ctrl1->GetRigidBody()->getBroadphaseHandle()->m_collisionFilterGroup = btBroadphaseProxy::AllFilter;
+ //todo: make this 'sensor'!
+
+ requestCollisionCallback(ctrl);
+ //printf("addSensor\n");
+}
+
+void CcdPhysicsEnvironment::removeCollisionCallback(PHY_IPhysicsController* ctrl)
+{
+ std::vector<CcdPhysicsController*>::iterator i =
+ std::find(m_triggerControllers.begin(), m_triggerControllers.end(), ctrl);
+ if (!(i == m_triggerControllers.end()))
+ {
+ std::swap(*i, m_triggerControllers.back());
+ m_triggerControllers.pop_back();
+ }
+}
+
+
+void CcdPhysicsEnvironment::removeSensor(PHY_IPhysicsController* ctrl)
+{
+ removeCollisionCallback(ctrl);
+ //printf("removeSensor\n");
+}
+void CcdPhysicsEnvironment::addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user)
+{
+ /* printf("addTouchCallback\n(response class = %i)\n",response_class);
+
+ //map PHY_ convention into SM_ convention
+ switch (response_class)
+ {
+ case PHY_FH_RESPONSE:
+ printf("PHY_FH_RESPONSE\n");
+ break;
+ case PHY_SENSOR_RESPONSE:
+ printf("PHY_SENSOR_RESPONSE\n");
+ break;
+ case PHY_CAMERA_RESPONSE:
+ printf("PHY_CAMERA_RESPONSE\n");
+ break;
+ case PHY_OBJECT_RESPONSE:
+ printf("PHY_OBJECT_RESPONSE\n");
+ break;
+ case PHY_STATIC_RESPONSE:
+ printf("PHY_STATIC_RESPONSE\n");
+ break;
+ default:
+ assert(0);
+ return;
+ }
+ */
+
+ m_triggerCallbacks[response_class] = callback;
+ m_triggerCallbacksUserPtrs[response_class] = user;
+
+}
+void CcdPhysicsEnvironment::requestCollisionCallback(PHY_IPhysicsController* ctrl)
+{
+ CcdPhysicsController* ccdCtrl = static_cast<CcdPhysicsController*>(ctrl);
+
+ //printf("requestCollisionCallback\n");
+ m_triggerControllers.push_back(ccdCtrl);
+}
+
+
+void CcdPhysicsEnvironment::CallbackTriggers()
+{
+
+ CcdPhysicsController* ctrl0=0,*ctrl1=0;
+
+ if (m_triggerCallbacks[PHY_OBJECT_RESPONSE] || (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints)))
+ {
+ //walk over all overlapping pairs, and if one of the involved bodies is registered for trigger callback, perform callback
+ int numManifolds = m_dynamicsWorld->getDispatcher()->getNumManifolds();
+ for (int i=0;i<numManifolds;i++)
+ {
+ btPersistentManifold* manifold = m_dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
+ int numContacts = manifold->getNumContacts();
+ if (numContacts)
+ {
+ if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints))
+ {
+ for (int j=0;j<numContacts;j++)
+ {
+ btVector3 color(1,0,0);
+ const btManifoldPoint& cp = manifold->getContactPoint(j);
+ if (m_debugDrawer)
+ m_debugDrawer->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),color);
+ }
+ }
+ btRigidBody* obj0 = static_cast<btRigidBody* >(manifold->getBody0());
+ btRigidBody* obj1 = static_cast<btRigidBody* >(manifold->getBody1());
+
+ //m_internalOwner is set in 'addPhysicsController'
+ CcdPhysicsController* ctrl0 = static_cast<CcdPhysicsController*>(obj0->getUserPointer());
+ CcdPhysicsController* ctrl1 = static_cast<CcdPhysicsController*>(obj1->getUserPointer());
+
+ std::vector<CcdPhysicsController*>::iterator i =
+ std::find(m_triggerControllers.begin(), m_triggerControllers.end(), ctrl0);
+ if (i == m_triggerControllers.end())
+ {
+ i = std::find(m_triggerControllers.begin(), m_triggerControllers.end(), ctrl1);
+ }
+
+ if (!(i == m_triggerControllers.end()))
+ {
+ m_triggerCallbacks[PHY_OBJECT_RESPONSE](m_triggerCallbacksUserPtrs[PHY_OBJECT_RESPONSE],
+ ctrl0,ctrl1,0);
+ }
+ }
+ }
+
+
+
+ }
+
+
+}
+
+
+
+
+
+
+#ifdef NEW_BULLET_VEHICLE_SUPPORT
+
+//complex constraint for vehicles
+PHY_IVehicle* CcdPhysicsEnvironment::getVehicleConstraint(int constraintId)
+{
+ int i;
+
+ int numVehicles = m_wrapperVehicles.size();
+ for (i=0;i<numVehicles;i++)
+ {
+ WrapperVehicle* wrapperVehicle = m_wrapperVehicles[i];
+ if (wrapperVehicle->GetVehicle()->getUserConstraintId() == constraintId)
+ return wrapperVehicle;
+ }
+
+ return 0;
+}
+
+#endif //NEW_BULLET_VEHICLE_SUPPORT
+
+
+int currentController = 0;
+int numController = 0;
+
+
+
+
+PHY_IPhysicsController* CcdPhysicsEnvironment::CreateSphereController(float radius,const PHY__Vector3& position)
+{
+
+ CcdConstructionInfo cinfo;
+ cinfo.m_collisionShape = new btSphereShape(radius);
+ cinfo.m_MotionState = 0;
+ cinfo.m_physicsEnv = this;
+ cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE | btCollisionObject::CF_KINEMATIC_OBJECT;
+ DefaultMotionState* motionState = new DefaultMotionState();
+ cinfo.m_MotionState = motionState;
+ motionState->m_worldTransform.setIdentity();
+ motionState->m_worldTransform.setOrigin(btVector3(position[0],position[1],position[2]));
+
+ CcdPhysicsController* sphereController = new CcdPhysicsController(cinfo);
+
+
+ return sphereController;
+}
+
+int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl0,class PHY_IPhysicsController* ctrl1,PHY_ConstraintType type,
+ float pivotX,float pivotY,float pivotZ,
+ float axisX,float axisY,float axisZ,
+ float axis1X,float axis1Y,float axis1Z,
+ float axis2X,float axis2Y,float axis2Z
+ )
+{
+
+
+ CcdPhysicsController* c0 = (CcdPhysicsController*)ctrl0;
+ CcdPhysicsController* c1 = (CcdPhysicsController*)ctrl1;
+
+ btRigidBody* rb0 = c0 ? c0->GetRigidBody() : 0;
+ btRigidBody* rb1 = c1 ? c1->GetRigidBody() : 0;
+
+ bool rb0static = rb0 ? rb0->isStaticOrKinematicObject() : true;
+ bool rb1static = rb1 ? rb1->isStaticOrKinematicObject() : true;
+
+
+ if (rb0static && rb1static)
+ return 0;
+
+ btVector3 pivotInA(pivotX,pivotY,pivotZ);
+ btVector3 pivotInB = rb1 ? rb1->getCenterOfMassTransform().inverse()(rb0->getCenterOfMassTransform()(pivotInA)) :
+ rb0->getCenterOfMassTransform() * pivotInA;
+ btVector3 axisInA(axisX,axisY,axisZ);
+
+
+ bool angularOnly = false;
+
+ switch (type)
+ {
+ case PHY_POINT2POINT_CONSTRAINT:
+ {
+
+ btPoint2PointConstraint* p2p = 0;
+
+ if (rb1)
+ {
+ p2p = new btPoint2PointConstraint(*rb0,
+ *rb1,pivotInA,pivotInB);
+ } else
+ {
+ p2p = new btPoint2PointConstraint(*rb0,
+ pivotInA);
+ }
+
+ m_dynamicsWorld->addConstraint(p2p);
+// m_constraints.push_back(p2p);
+
+ p2p->setUserConstraintId(gConstraintUid++);
+ p2p->setUserConstraintType(type);
+ //64 bit systems can't cast pointer to int. could use size_t instead.
+ return p2p->getUserConstraintId();
+
+ break;
+ }
+
+ case PHY_GENERIC_6DOF_CONSTRAINT:
+ {
+ btGeneric6DofConstraint* genericConstraint = 0;
+
+ if (rb1)
+ {
+ btTransform frameInA;
+ btTransform frameInB;
+
+ btVector3 axis1(axis1X,axis1Y,axis1Z), axis2(axis2X,axis2Y,axis2Z);
+ if (axis1.length() == 0.0)
+ {
+ btPlaneSpace1( axisInA, axis1, axis2 );
+ }
+
+ frameInA.getBasis().setValue( axisInA.x(), axis1.x(), axis2.x(),
+ axisInA.y(), axis1.y(), axis2.y(),
+ axisInA.z(), axis1.z(), axis2.z() );
+ frameInA.setOrigin( pivotInA );
+
+ btTransform inv = rb1->getCenterOfMassTransform().inverse();
+
+ btTransform globalFrameA = rb0->getCenterOfMassTransform() * frameInA;
+
+ frameInB = inv * globalFrameA;
+
+ genericConstraint = new btGeneric6DofConstraint(
+ *rb0,*rb1,
+ frameInA,frameInB);
+
+
+ } else
+ {
+ static btRigidBody s_fixedObject2( 0,0,0);
+ btTransform frameInA;
+ btTransform frameInB;
+
+ btVector3 axis1, axis2;
+ btPlaneSpace1( axisInA, axis1, axis2 );
+
+ frameInA.getBasis().setValue( axisInA.x(), axis1.x(), axis2.x(),
+ axisInA.y(), axis1.y(), axis2.y(),
+ axisInA.z(), axis1.z(), axis2.z() );
+
+ frameInA.setOrigin( pivotInA );
+
+ ///frameInB in worldspace
+ frameInB = rb0->getCenterOfMassTransform() * frameInA;
+
+ genericConstraint = new btGeneric6DofConstraint(
+ *rb0,s_fixedObject2,
+ frameInA,frameInB);
+ }
+
+ if (genericConstraint)
+ {
+ //m_constraints.push_back(genericConstraint);
+ m_dynamicsWorld->addConstraint(genericConstraint);
+ genericConstraint->setUserConstraintId(gConstraintUid++);
+ genericConstraint->setUserConstraintType(type);
+ //64 bit systems can't cast pointer to int. could use size_t instead.
+ return genericConstraint->getUserConstraintId();
+ }
+
+ break;
+ }
+ case PHY_CONE_TWIST_CONSTRAINT:
+ {
+ btConeTwistConstraint* coneTwistContraint = 0;
+
+
+ if (rb1)
+ {
+ btTransform frameInA;
+ btTransform frameInB;
+
+ btVector3 axis1(axis1X,axis1Y,axis1Z), axis2(axis2X,axis2Y,axis2Z);
+ if (axis1.length() == 0.0)
+ {
+ btPlaneSpace1( axisInA, axis1, axis2 );
+ }
+
+ frameInA.getBasis().setValue( axisInA.x(), axis1.x(), axis2.x(),
+ axisInA.y(), axis1.y(), axis2.y(),
+ axisInA.z(), axis1.z(), axis2.z() );
+ frameInA.setOrigin( pivotInA );
+
+ btTransform inv = rb1->getCenterOfMassTransform().inverse();
+
+ btTransform globalFrameA = rb0->getCenterOfMassTransform() * frameInA;
+
+ frameInB = inv * globalFrameA;
+
+ coneTwistContraint = new btConeTwistConstraint( *rb0,*rb1,
+ frameInA,frameInB);
+
+
+ } else
+ {
+ static btRigidBody s_fixedObject2( 0,0,0);
+ btTransform frameInA;
+ btTransform frameInB;
+
+ btVector3 axis1, axis2;
+ btPlaneSpace1( axisInA, axis1, axis2 );
+
+ frameInA.getBasis().setValue( axisInA.x(), axis1.x(), axis2.x(),
+ axisInA.y(), axis1.y(), axis2.y(),
+ axisInA.z(), axis1.z(), axis2.z() );
+
+ frameInA.setOrigin( pivotInA );
+
+ ///frameInB in worldspace
+ frameInB = rb0->getCenterOfMassTransform() * frameInA;
+
+ coneTwistContraint = new btConeTwistConstraint(
+ *rb0,s_fixedObject2,
+ frameInA,frameInB);
+ }
+
+ if (coneTwistContraint)
+ {
+ //m_constraints.push_back(genericConstraint);
+ m_dynamicsWorld->addConstraint(coneTwistContraint);
+ coneTwistContraint->setUserConstraintId(gConstraintUid++);
+ coneTwistContraint->setUserConstraintType(type);
+ //64 bit systems can't cast pointer to int. could use size_t instead.
+ return coneTwistContraint->getUserConstraintId();
+ }
+
+
+
+ break;
+ }
+ case PHY_ANGULAR_CONSTRAINT:
+ angularOnly = true;
+
+
+ case PHY_LINEHINGE_CONSTRAINT:
+ {
+ btHingeConstraint* hinge = 0;
+
+ if (rb1)
+ {
+ btVector3 axisInB = rb1 ?
+ (rb1->getCenterOfMassTransform().getBasis().inverse()*(rb0->getCenterOfMassTransform().getBasis() * axisInA)) :
+ rb0->getCenterOfMassTransform().getBasis() * axisInA;
+
+ hinge = new btHingeConstraint(
+ *rb0,
+ *rb1,pivotInA,pivotInB,axisInA,axisInB);
+
+
+ } else
+ {
+ hinge = new btHingeConstraint(*rb0,
+ pivotInA,axisInA);
+
+ }
+ hinge->setAngularOnly(angularOnly);
+
+ //m_constraints.push_back(hinge);
+ m_dynamicsWorld->addConstraint(hinge);
+ hinge->setUserConstraintId(gConstraintUid++);
+ hinge->setUserConstraintType(type);
+ //64 bit systems can't cast pointer to int. could use size_t instead.
+ return hinge->getUserConstraintId();
+ break;
+ }
+#ifdef NEW_BULLET_VEHICLE_SUPPORT
+
+ case PHY_VEHICLE_CONSTRAINT:
+ {
+ btRaycastVehicle::btVehicleTuning* tuning = new btRaycastVehicle::btVehicleTuning();
+ btRigidBody* chassis = rb0;
+ btDefaultVehicleRaycaster* raycaster = new btDefaultVehicleRaycaster(m_dynamicsWorld);
+ btRaycastVehicle* vehicle = new btRaycastVehicle(*tuning,chassis,raycaster);
+ WrapperVehicle* wrapperVehicle = new WrapperVehicle(vehicle,ctrl0);
+ m_wrapperVehicles.push_back(wrapperVehicle);
+ m_dynamicsWorld->addVehicle(vehicle);
+ vehicle->setUserConstraintId(gConstraintUid++);
+ vehicle->setUserConstraintType(type);
+ return vehicle->getUserConstraintId();
+
+ break;
+ };
+#endif //NEW_BULLET_VEHICLE_SUPPORT
+
+ default:
+ {
+ }
+ };
+
+ //btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB
+
+ return 0;
+
+}
+
+
+
+PHY_IPhysicsController* CcdPhysicsEnvironment::CreateConeController(float coneradius,float coneheight)
+{
+ CcdConstructionInfo cinfo;
+ cinfo.m_collisionShape = new btConeShape(coneradius,coneheight);
+ cinfo.m_MotionState = 0;
+ cinfo.m_physicsEnv = this;
+ cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE;
+ DefaultMotionState* motionState = new DefaultMotionState();
+ cinfo.m_MotionState = motionState;
+ motionState->m_worldTransform.setIdentity();
+// motionState->m_worldTransform.setOrigin(btVector3(position[0],position[1],position[2]));
+
+ CcdPhysicsController* sphereController = new CcdPhysicsController(cinfo);
+
+
+ return sphereController;
+}
+
+float CcdPhysicsEnvironment::getAppliedImpulse(int constraintid)
+{
+ int i;
+ int numConstraints = m_dynamicsWorld->getNumConstraints();
+ for (i=0;i<numConstraints;i++)
+ {
+ btTypedConstraint* constraint = m_dynamicsWorld->getConstraint(i);
+ if (constraint->getUserConstraintId() == constraintid)
+ {
+ return constraint->getAppliedImpulse();
+ }
+ }
+
+ return 0.f;
+}
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
new file mode 100644
index 00000000000..66a6ed59c17
--- /dev/null
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
@@ -0,0 +1,242 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef CCDPHYSICSENVIRONMENT
+#define CCDPHYSICSENVIRONMENT
+
+#include "PHY_IPhysicsEnvironment.h"
+#include <vector>
+class CcdPhysicsController;
+#include "LinearMath/btVector3.h"
+#include "LinearMath/btTransform.h"
+
+
+
+
+class btTypedConstraint;
+class btSimulationIslandManager;
+class btCollisionDispatcher;
+class btDispatcher;
+//#include "btBroadphaseInterface.h"
+
+//switch on/off new vehicle support
+#define NEW_BULLET_VEHICLE_SUPPORT 1
+
+#include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h"
+
+class WrapperVehicle;
+class btPersistentManifold;
+class btBroadphaseInterface;
+class btOverlappingPairCache;
+class btIDebugDraw;
+class PHY_IVehicle;
+
+/// CcdPhysicsEnvironment is an experimental mainloop for physics simulation using optional continuous collision detection.
+/// Physics Environment takes care of stepping the simulation and is a container for physics entities.
+/// It stores rigidbodies,constraints, materials etc.
+/// A derived class may be able to 'construct' entities by loading and/or converting
+class CcdPhysicsEnvironment : public PHY_IPhysicsEnvironment
+{
+ btVector3 m_gravity;
+
+
+
+protected:
+ btIDebugDraw* m_debugDrawer;
+ //solver iterations
+ int m_numIterations;
+
+ //timestep subdivisions
+ int m_numTimeSubSteps;
+
+
+ int m_ccdMode;
+ int m_solverType;
+ int m_profileTimings;
+ bool m_enableSatCollisionDetection;
+
+ btContactSolverInfo m_solverInfo;
+
+
+ public:
+ CcdPhysicsEnvironment(btDispatcher* dispatcher=0, btOverlappingPairCache* pairCache=0);
+
+ virtual ~CcdPhysicsEnvironment();
+
+ /////////////////////////////////////
+ //PHY_IPhysicsEnvironment interface
+ /////////////////////////////////////
+
+ /// Perform an integration step of duration 'timeStep'.
+
+ virtual void setDebugDrawer(btIDebugDraw* debugDrawer);
+
+ virtual void setNumIterations(int numIter);
+ virtual void setNumTimeSubSteps(int numTimeSubSteps)
+ {
+ m_numTimeSubSteps = numTimeSubSteps;
+ }
+ virtual void setDeactivationTime(float dTime);
+ virtual void setDeactivationLinearTreshold(float linTresh) ;
+ virtual void setDeactivationAngularTreshold(float angTresh) ;
+ virtual void setContactBreakingTreshold(float contactBreakingTreshold) ;
+ virtual void setCcdMode(int ccdMode);
+ virtual void setSolverType(int solverType);
+ virtual void setSolverSorConstant(float sor);
+ virtual void setSolverTau(float tau);
+ virtual void setSolverDamping(float damping);
+ virtual void setLinearAirDamping(float damping);
+ virtual void setUseEpa(bool epa) ;
+
+ virtual void beginFrame();
+ virtual void endFrame() {};
+ /// Perform an integration step of duration 'timeStep'.
+ virtual bool proceedDeltaTime(double curTime,float timeStep);
+// virtual bool proceedDeltaTimeOneStep(float timeStep);
+
+ virtual void setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep){};
+ //returns 0.f if no fixed timestep is used
+
+ virtual float getFixedTimeStep(){ return 0.f;};
+
+ virtual void setDebugMode(int debugMode);
+
+ virtual void setGravity(float x,float y,float z);
+
+ virtual int createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type,
+ float pivotX,float pivotY,float pivotZ,
+ float axisX,float axisY,float axisZ,
+ float axis1X=0,float axis1Y=0,float axis1Z=0,
+ float axis2X=0,float axis2Y=0,float axis2Z=0
+ );
+
+
+ //Following the COLLADA physics specification for constraints
+ virtual int createUniversalD6Constraint(
+ class PHY_IPhysicsController* ctrlRef,class PHY_IPhysicsController* ctrlOther,
+ btTransform& localAttachmentFrameRef,
+ btTransform& localAttachmentOther,
+ const btVector3& linearMinLimits,
+ const btVector3& linearMaxLimits,
+ const btVector3& angularMinLimits,
+ const btVector3& angularMaxLimits
+ );
+
+ virtual void setConstraintParam(int constraintId,int param,float value,float value1);
+
+ virtual void removeConstraint(int constraintid);
+
+ virtual float getAppliedImpulse(int constraintid);
+
+
+ virtual void CallbackTriggers();
+
+
+#ifdef NEW_BULLET_VEHICLE_SUPPORT
+ //complex constraint for vehicles
+ virtual PHY_IVehicle* getVehicleConstraint(int constraintId);
+#else
+ virtual class PHY_IVehicle* getVehicleConstraint(int constraintId)
+ {
+ return 0;
+ }
+#endif //NEW_BULLET_VEHICLE_SUPPORT
+
+ btTypedConstraint* getConstraintById(int constraintId);
+
+ virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ,
+ float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ);
+
+
+ //Methods for gamelogic collision/physics callbacks
+ virtual void addSensor(PHY_IPhysicsController* ctrl);
+ virtual void removeSensor(PHY_IPhysicsController* ctrl);
+ virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user);
+ virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl);
+ virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl);
+
+ virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position);
+ virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight);
+
+
+ virtual int getNumContactPoints();
+
+ virtual void getContactPoint(int i,float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ);
+
+ //////////////////////
+ //CcdPhysicsEnvironment interface
+ ////////////////////////
+
+ void addCcdPhysicsController(CcdPhysicsController* ctrl);
+
+ void removeCcdPhysicsController(CcdPhysicsController* ctrl);
+
+ btBroadphaseInterface* getBroadphase();
+
+
+
+
+
+ bool IsSatCollisionDetectionEnabled() const
+ {
+ return m_enableSatCollisionDetection;
+ }
+
+ void EnableSatCollisionDetection(bool enableSat)
+ {
+ m_enableSatCollisionDetection = enableSat;
+ }
+
+
+ int GetNumControllers();
+
+ CcdPhysicsController* GetPhysicsController( int index);
+
+
+
+ const btPersistentManifold* GetManifold(int index) const;
+
+
+ void SyncMotionStates(float timeStep);
+
+
+
+ class btConstraintSolver* GetConstraintSolver();
+
+ protected:
+
+
+
+
+ std::vector<CcdPhysicsController*> m_controllers;
+
+ std::vector<CcdPhysicsController*> m_triggerControllers;
+
+ PHY_ResponseCallback m_triggerCallbacks[PHY_NUM_RESPONSE];
+ void* m_triggerCallbacksUserPtrs[PHY_NUM_RESPONSE];
+
+ std::vector<WrapperVehicle*> m_wrapperVehicles;
+
+ class btDynamicsWorld* m_dynamicsWorld;
+
+ class btConstraintSolver* m_solver;
+
+ bool m_scalingPropagated;
+
+
+
+};
+
+#endif //CCDPHYSICSENVIRONMENT
diff --git a/source/gameengine/Physics/Bullet/Makefile b/source/gameengine/Physics/Bullet/Makefile
new file mode 100644
index 00000000000..a5643b60c94
--- /dev/null
+++ b/source/gameengine/Physics/Bullet/Makefile
@@ -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 *****
+#
+#
+
+LIBNAME = blbullet
+DIR = $(OCGDIR)/gameengine/blphys/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(NAN_BULLET2)/include
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../Physics/common
+CPPFLAGS += -I../../Physics/Dummy
diff --git a/source/gameengine/Physics/Bullet/SConscript b/source/gameengine/Physics/Bullet/SConscript
new file mode 100644
index 00000000000..dd6eab0f018
--- /dev/null
+++ b/source/gameengine/Physics/Bullet/SConscript
@@ -0,0 +1,15 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = 'CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp'
+
+incs = '. ../common'
+
+incs += ' ' + env['BF_BULLET_INC']
+
+cflags = []
+if env['OURPLATFORM']=='win32-vc':
+ cflags.append('/GR')
+ cflags.append('/O2')
+
+env.BlenderLib ( 'bf_bullet', Split(sources), Split(incs), [], libtype=['game','player'], priority=[15,90] )
diff --git a/source/gameengine/Physics/Dummy/CMakeLists.txt b/source/gameengine/Physics/Dummy/CMakeLists.txt
new file mode 100644
index 00000000000..4db44a5d42c
--- /dev/null
+++ b/source/gameengine/Physics/Dummy/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 *****
+
+SET(SRC DummyPhysicsEnvironment.cpp)
+
+SET(INC
+ .
+ ../common
+)
+
+BLENDERLIB(bf_dummy "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_dummy', Split(sources), Split(incs), [], libtype=['game','player'], priority=[10,100] )
diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp
new file mode 100644
index 00000000000..b40d1b430bb
--- /dev/null
+++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp
@@ -0,0 +1,121 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "DummyPhysicsEnvironment.h"
+#include "PHY_IMotionState.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+DummyPhysicsEnvironment::DummyPhysicsEnvironment()
+{
+ // create physicsengine data
+}
+
+
+
+DummyPhysicsEnvironment::~DummyPhysicsEnvironment()
+{
+ //destroy physicsengine data
+}
+
+void DummyPhysicsEnvironment::beginFrame()
+{
+ // beginning of logic frame: apply forces
+}
+
+void DummyPhysicsEnvironment::endFrame()
+{
+ // end of logic frame: clear forces
+}
+
+
+
+bool DummyPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep)
+{
+ //step physics simulation, typically perform
+
+ //collision detection
+ //solve constraints
+ //integrate solution
+ // return true if an update was done.
+ return true;
+}
+void DummyPhysicsEnvironment::setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep)
+{
+}
+
+float DummyPhysicsEnvironment::getFixedTimeStep()
+{
+ return 0.f;
+}
+
+
+
+
+void DummyPhysicsEnvironment::setGravity(float x,float y,float z)
+{
+}
+
+
+
+
+
+
+
+int DummyPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type,
+ float pivotX,float pivotY,float pivotZ,float axisX,float axisY,float axisZ,
+ float axis1X,float axis1Y,float axis1Z,
+ float axis2X,float axis2Y,float axis2Z
+
+ )
+{
+
+ int constraintid = 0;
+ return constraintid;
+
+}
+
+void DummyPhysicsEnvironment::removeConstraint(int constraintid)
+{
+ if (constraintid)
+ {
+ }
+}
+
+PHY_IPhysicsController* DummyPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ,
+ float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ)
+{
+ //collision detection / raytesting
+ return NULL;
+}
+
diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
new file mode 100644
index 00000000000..4fc970da699
--- /dev/null
+++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.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): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef _DUMMYPHYSICSENVIRONMENT
+#define _DUMMYPHYSICSENVIRONMENT
+
+#include "PHY_IPhysicsEnvironment.h"
+
+/**
+* DummyPhysicsEnvironment is an empty placeholder
+* Alternatives are ODE,Sumo and Dynamo PhysicsEnvironments
+* Use DummyPhysicsEnvironment as a base to integrate your own physics engine
+* Physics Environment takes care of stepping the simulation and is a container for physics entities (rigidbodies,constraints, materials etc.)
+*
+* A derived class may be able to 'construct' entities by loading and/or converting
+*/
+class DummyPhysicsEnvironment : public PHY_IPhysicsEnvironment
+{
+
+public:
+ DummyPhysicsEnvironment ();
+ virtual ~DummyPhysicsEnvironment ();
+ virtual void beginFrame();
+ virtual void endFrame();
+// Perform an integration step of duration 'timeStep'.
+ virtual bool proceedDeltaTime(double curTime,float timeStep);
+ virtual void setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep);
+ virtual float getFixedTimeStep();
+
+ virtual void setGravity(float x,float y,float z);
+
+ virtual int createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type,
+ float pivotX,float pivotY,float pivotZ,
+ float axisX,float axisY,float axisZ,
+ float axis1X=0,float axis1Y=0,float axis1Z=0,
+ float axis2X=0,float axis2Y=0,float axis2Z=0
+ );
+
+ virtual void removeConstraint(int constraintid);
+
+ //complex constraint for vehicles
+ virtual PHY_IVehicle* getVehicleConstraint(int constraintId)
+ {
+ return 0;
+ }
+
+ virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ,
+ float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ);
+
+
+ //gamelogic callbacks
+ virtual void addSensor(PHY_IPhysicsController* ctrl) {}
+ virtual void removeSensor(PHY_IPhysicsController* ctrl) {}
+ virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user)
+ {
+ }
+ virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl) {}
+ virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position) {return 0;}
+ virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight) { return 0;}
+
+ virtual void setConstraintParam(int constraintId,int param,float value,float value1)
+ {
+ }
+
+};
+
+#endif //_DUMMYPHYSICSENVIRONMENT
+
diff --git a/source/gameengine/Physics/Dummy/Makefile b/source/gameengine/Physics/Dummy/Makefile
new file mode 100644
index 00000000000..0ecb3fa786a
--- /dev/null
+++ b/source/gameengine/Physics/Dummy/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): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = dummy
+DIR = $(OCGDIR)/gameengine/blphys/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO)/include -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../Physics/common
+CPPFLAGS += -I../../Physics/Dummy
diff --git a/source/gameengine/Physics/Dummy/SConscript b/source/gameengine/Physics/Dummy/SConscript
new file mode 100644
index 00000000000..e24b150531f
--- /dev/null
+++ b/source/gameengine/Physics/Dummy/SConscript
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = 'DummyPhysicsEnvironment.cpp'
+
+incs = '. ../common'
+
+env.BlenderLib ( 'bf_dummy', Split(sources), Split(incs), [], libtype=['game','player'], priority=[10,100] )
diff --git a/source/gameengine/Physics/Makefile b/source/gameengine/Physics/Makefile
new file mode 100644
index 00000000000..62e433cb72c
--- /dev/null
+++ b/source/gameengine/Physics/Makefile
@@ -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 *****
+#
+# Bounces make to subdirectories.
+
+include nan_definitions.mk
+
+SOURCEDIR = source/gameengine/Physics
+DIR = $(OCGDIR)/gameengine/blphys
+DIRS = common Sumo Dummy Bullet
+#DIRS += BlOde
+
+include nan_subdirs.mk
diff --git a/source/gameengine/Physics/Sumo/CMakeLists.txt b/source/gameengine/Physics/Sumo/CMakeLists.txt
new file mode 100644
index 00000000000..d552a9a821c
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/CMakeLists.txt
@@ -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) 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
+ SumoPHYCallbackBridge.cpp
+ SumoPhysicsController.cpp
+ SumoPhysicsEnvironment.cpp
+ Fuzzics/src/SM_FhObject.cpp
+ Fuzzics/src/SM_Object.cpp
+ Fuzzics/src/SM_Scene.cpp
+ Fuzzics/src/SM_MotionState.cpp
+)
+
+SET(INC
+ .
+ ../common
+ Fuzzics/include
+ ../../../../intern/moto/include
+ ../../../../extern/solid
+)
+
+BLENDERLIB(bf_sumo "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_sumo', sources, incs, [], libtype=['game2','player'], priority=[30, 70] , compileflags=cflags)
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/Makefile b/source/gameengine/Physics/Sumo/Fuzzics/Makefile
new file mode 100644
index 00000000000..557be7a1bd4
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/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/gameengine/Physics/Sumo/Fuzzics
+DIRS = src
+
+include nan_subdirs.mk
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Callback.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Callback.h
new file mode 100644
index 00000000000..a43ddbec483
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Callback.h
@@ -0,0 +1,10 @@
+#ifndef SM_CALLBACK_H
+#define SM_CALLBACK_H
+
+class SM_Callback {
+public:
+ virtual void do_me() = 0;
+};
+
+#endif
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_ClientObjectInfo.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_ClientObjectInfo.h
new file mode 100644
index 00000000000..6749e7957ec
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_ClientObjectInfo.h
@@ -0,0 +1,16 @@
+#ifndef __SM_CLIENTOBJECT_INFO_H
+#define __SM_CLIENTOBJECT_INFO_H
+
+/**
+ * Client Type and Additional Info. This structure can be use instead of a bare void* pointer, for safeness, and additional info for callbacks
+ */
+
+struct SM_ClientObjectInfo
+{
+ int m_type;
+ void* m_clientobject1;
+ void* m_auxilary_info;
+};
+
+#endif //__SM_CLIENTOBJECT_INFO_H
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Debug.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Debug.h
new file mode 100644
index 00000000000..48d5906e53d
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Debug.h
@@ -0,0 +1,26 @@
+
+
+#ifndef __SM_DEBUG_H__
+#define __SM_DEBUG_H__
+
+/* Comment this to disable all SUMO debugging printfs */
+
+#define SM_DEBUG
+
+#ifdef SM_DEBUG
+
+#include <stdio.h>
+
+/* Uncomment this to printf all ray casts */
+//#define SM_DEBUG_RAYCAST
+
+/* Uncomment this to printf collision callbacks */
+//#define SM_DEBUG_BOING
+
+/* Uncomment this to printf Xform matrix calculations */
+//#define SM_DEBUG_XFORM
+
+#endif /* SM_DEBUG */
+
+#endif /* __SM_DEBUG_H__ */
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_FhObject.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_FhObject.h
new file mode 100644
index 00000000000..4db531d945d
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_FhObject.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 SM_FHOBJECT_H
+#define SM_FHOBJECT_H
+
+#include "SM_Object.h"
+
+class SM_FhObject : public SM_Object {
+public:
+ virtual ~SM_FhObject();
+ SM_FhObject(DT_ShapeHandle rayshape, MT_Vector3 ray, SM_Object *parent_object);
+
+ const MT_Vector3& getRay() const { return m_ray; }
+ MT_Point3 getSpot() const { return getPosition() + m_ray; }
+ const MT_Vector3& getRayDirection() const { return m_ray_direction; }
+ SM_Object *getParentObject() const { return m_parent_object; }
+
+ static DT_Bool ray_hit(void *client_data,
+ void *object1,
+ void *object2,
+ const DT_CollData *coll_data);
+
+private:
+ MT_Vector3 m_ray;
+ MT_Vector3 m_ray_direction;
+ SM_Object *m_parent_object;
+};
+
+#endif
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_MotionState.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_MotionState.h
new file mode 100644
index 00000000000..08e29265d0c
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_MotionState.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): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef SM_MOTIONSTATE_H
+#define SM_MOTIONSTATE_H
+
+#include "MT_Transform.h"
+
+class SM_MotionState {
+public:
+ SM_MotionState() :
+ m_time(0.0),
+ m_pos(0.0, 0.0, 0.0),
+ m_orn(0.0, 0.0, 0.0, 1.0),
+ m_lin_vel(0.0, 0.0, 0.0),
+ m_ang_vel(0.0, 0.0, 0.0)
+ {}
+
+ void setPosition(const MT_Point3& pos) { m_pos = pos; }
+ void setOrientation(const MT_Quaternion& orn) { m_orn = orn; }
+ void setLinearVelocity(const MT_Vector3& lin_vel) { m_lin_vel = lin_vel; }
+ void setAngularVelocity(const MT_Vector3& ang_vel) { m_ang_vel = ang_vel; }
+ void setTime(MT_Scalar time) { m_time = time; }
+
+ const MT_Point3& getPosition() const { return m_pos; }
+ const MT_Quaternion& getOrientation() const { return m_orn; }
+ const MT_Vector3& getLinearVelocity() const { return m_lin_vel; }
+ const MT_Vector3& getAngularVelocity() const { return m_ang_vel; }
+
+ MT_Scalar getTime() const { return m_time; }
+
+ void integrateMidpoint(MT_Scalar timeStep, const SM_MotionState &prev_state, const MT_Vector3 &velocity, const MT_Quaternion& ang_vel);
+ void integrateBackward(MT_Scalar timeStep, const MT_Vector3 &velocity, const MT_Quaternion& ang_vel);
+ void integrateForward(MT_Scalar timeStep, const SM_MotionState &prev_state);
+
+ void lerp(const SM_MotionState &prev, const SM_MotionState &next);
+ void lerp(MT_Scalar t, const SM_MotionState &other);
+
+ virtual MT_Transform getTransform() const {
+ return MT_Transform(m_pos, m_orn);
+ }
+
+protected:
+ MT_Scalar m_time;
+ MT_Point3 m_pos;
+ MT_Quaternion m_orn;
+ MT_Vector3 m_lin_vel;
+ MT_Vector3 m_ang_vel;
+};
+
+#endif
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Object.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Object.h
new file mode 100644
index 00000000000..8b70bbc5779
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Object.h
@@ -0,0 +1,396 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 SM_OBJECT_H
+#define SM_OBJECT_H
+
+#include <vector>
+
+#include <SOLID/SOLID.h>
+
+#include "SM_Callback.h"
+#include "SM_MotionState.h"
+#include <stdio.h>
+
+class SM_FhObject;
+
+/** Properties of dynamic objects */
+struct SM_ShapeProps {
+ MT_Scalar m_mass; ///< Total mass
+ MT_Scalar m_radius; ///< Bound sphere size
+ MT_Vector3 m_inertia; ///< Inertia, should be a tensor some time
+ MT_Scalar m_lin_drag; ///< Linear drag (air, water) 0 = concrete, 1 = vacuum
+ MT_Scalar m_ang_drag; ///< Angular drag
+ MT_Scalar m_friction_scaling[3]; ///< Scaling for anisotropic friction. Component in range [0, 1]
+ bool m_do_anisotropic; ///< Should I do anisotropic friction?
+ bool m_do_fh; ///< Should the object have a linear Fh spring?
+ bool m_do_rot_fh; ///< Should the object have an angular Fh spring?
+};
+
+
+/** Properties of collidable objects (non-ghost objects) */
+struct SM_MaterialProps {
+ MT_Scalar m_restitution; ///< restitution of energy after a collision 0 = inelastic, 1 = elastic
+ MT_Scalar m_friction; ///< Coulomb friction (= ratio between the normal en maximum friction force)
+ MT_Scalar m_fh_spring; ///< Spring constant (both linear and angular)
+ MT_Scalar m_fh_damping; ///< Damping factor (linear and angular) in range [0, 1]
+ MT_Scalar m_fh_distance; ///< The range above the surface where Fh is active.
+ bool m_fh_normal; ///< Should the object slide off slopes?
+};
+
+class SM_ClientObject
+{
+public:
+ SM_ClientObject() {}
+ virtual ~SM_ClientObject() {}
+
+ virtual bool hasCollisionCallback() = 0;
+};
+
+/**
+ * SM_Object is an internal part of the Sumo physics engine.
+ *
+ * It encapsulates an object in the physics scene, and is responsible
+ * for calculating the collision response of objects.
+ */
+class SM_Object
+{
+public:
+ SM_Object() ;
+ SM_Object(
+ DT_ShapeHandle shape,
+ const SM_MaterialProps *materialProps,
+ const SM_ShapeProps *shapeProps,
+ SM_Object *dynamicParent
+ );
+ virtual ~SM_Object();
+
+ bool isDynamic() const;
+
+ /* nzc experimental. There seem to be two places where kinematics
+ * are evaluated: proceedKinematic (called from SM_Scene) and
+ * proceed() in this object. I'll just try and bunge these out for
+ * now. */
+
+ void suspend(void);
+ void resume(void);
+
+ void suspendDynamics();
+
+ void restoreDynamics();
+
+ bool isGhost() const;
+
+ void suspendMaterial();
+
+ void restoreMaterial();
+
+ SM_FhObject *getFhObject() const;
+
+ void registerCallback(SM_Callback& callback);
+
+ void calcXform();
+ void notifyClient();
+ void updateInvInertiaTensor();
+
+
+ // Save the current state information for use in the
+ // velocity computation in the next frame.
+
+ void proceedKinematic(MT_Scalar timeStep);
+
+ void saveReactionForce(MT_Scalar timeStep) ;
+
+ void clearForce() ;
+
+ void clearMomentum() ;
+
+ void setMargin(MT_Scalar margin) ;
+
+ MT_Scalar getMargin() const ;
+
+ const SM_MaterialProps *getMaterialProps() const ;
+
+ const SM_ShapeProps *getShapeProps() const ;
+
+ void setPosition(const MT_Point3& pos);
+ void setOrientation(const MT_Quaternion& orn);
+ void setScaling(const MT_Vector3& scaling);
+
+ /**
+ * set an external velocity. This velocity complements
+ * the physics velocity. So setting it does not override the
+ * physics velocity. It is your responsibility to clear
+ * this external velocity. This velocity is not subject to
+ * friction or damping.
+ */
+ void setExternalLinearVelocity(const MT_Vector3& lin_vel) ;
+ void addExternalLinearVelocity(const MT_Vector3& lin_vel) ;
+
+ /** Override the physics velocity */
+ void addLinearVelocity(const MT_Vector3& lin_vel);
+ void setLinearVelocity(const MT_Vector3& lin_vel);
+
+ /**
+ * Set an external angular velocity. This velocity complemetns
+ * the physics angular velocity so does not override it. It is
+ * your responsibility to clear this velocity. This velocity
+ * is not subject to friction or damping.
+ */
+ void setExternalAngularVelocity(const MT_Vector3& ang_vel) ;
+ void addExternalAngularVelocity(const MT_Vector3& ang_vel);
+
+ /** Override the physics angular velocity */
+ void addAngularVelocity(const MT_Vector3& ang_vel);
+ void setAngularVelocity(const MT_Vector3& ang_vel);
+
+ /** Clear the external velocities */
+ void clearCombinedVelocities();
+
+ /**
+ * Tell the physics system to combine the external velocity
+ * with the physics velocity.
+ */
+ void resolveCombinedVelocities(
+ const MT_Vector3 & lin_vel,
+ const MT_Vector3 & ang_vel
+ ) ;
+
+
+
+ MT_Scalar getInvMass() const;
+
+ const MT_Vector3& getInvInertia() const ;
+
+ const MT_Matrix3x3& getInvInertiaTensor() const;
+
+ void applyForceField(const MT_Vector3& accel) ;
+
+ void applyCenterForce(const MT_Vector3& force) ;
+
+ void applyTorque(const MT_Vector3& torque) ;
+
+ /**
+ * Apply an impulse to the object. The impulse will be split into
+ * angular and linear components.
+ * @param attach point to apply the impulse to (in world coordinates)
+ */
+ void applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse) ;
+
+ /**
+ * Applies an impulse through the center of this object. (ie the angular
+ * velocity will not change.
+ */
+ void applyCenterImpulse(const MT_Vector3& impulse);
+ /**
+ * Applies an angular impulse.
+ */
+ void applyAngularImpulse(const MT_Vector3& impulse);
+
+ MT_Point3 getWorldCoord(const MT_Point3& local) const;
+ MT_Point3 getLocalCoord(const MT_Point3& world) const;
+
+ MT_Vector3 getVelocity(const MT_Point3& local) const;
+
+
+ const MT_Vector3& getReactionForce() const ;
+
+ void getMatrix(double *m) const ;
+
+ const double *getMatrix() const ;
+
+ // Still need this???
+ const MT_Transform& getScaledTransform() const;
+
+ DT_ObjectHandle getObjectHandle() const ;
+ DT_ShapeHandle getShapeHandle() const ;
+
+ SM_Object *getDynamicParent() ;
+
+ void integrateForces(MT_Scalar timeStep);
+ void integrateMomentum(MT_Scalar timeSteo);
+
+ void setRigidBody(bool is_rigid_body) ;
+
+ bool isRigidBody() const ;
+
+ // This is the callback for handling collisions of dynamic objects
+ static
+ DT_Bool
+ boing(
+ void *client_data,
+ void *object1,
+ void *object2,
+ const DT_CollData *coll_data
+ );
+
+ static
+ DT_Bool
+ fix(
+ void *client_data,
+ void *object1,
+ void *object2,
+ const DT_CollData *coll_data
+ );
+
+
+ SM_ClientObject *getClientObject() { return m_client_object; }
+ void setClientObject(SM_ClientObject *client_object) { m_client_object = client_object; }
+ void setPhysicsClientObject(void* physicsClientObject)
+ {
+ m_physicsClientObject = physicsClientObject;
+ }
+ void* getPhysicsClientObject() {
+ return m_physicsClientObject;
+ }
+ void relax();
+
+ SM_MotionState &getCurrentFrame();
+ SM_MotionState &getPreviousFrame();
+ SM_MotionState &getNextFrame();
+
+ const SM_MotionState &getCurrentFrame() const;
+ const SM_MotionState &getPreviousFrame() const;
+ const SM_MotionState &getNextFrame() const;
+
+ // Motion state functions
+ const MT_Point3& getPosition() const;
+ const MT_Quaternion& getOrientation() const;
+ const MT_Vector3& getLinearVelocity() const;
+ const MT_Vector3& getAngularVelocity() const;
+
+ MT_Scalar getTime() const;
+
+ void setTime(MT_Scalar time);
+
+ void interpolate(MT_Scalar timeStep);
+ void endFrame();
+
+private:
+ friend class Contact;
+ // Tweak parameters
+ static MT_Scalar ImpulseThreshold;
+
+ // return the actual linear_velocity of this object this
+ // is the addition of m_combined_lin_vel and m_lin_vel.
+
+ const
+ MT_Vector3
+ actualLinVelocity(
+ ) const ;
+
+ const
+ MT_Vector3
+ actualAngVelocity(
+ ) const ;
+
+ void dynamicCollision(const MT_Point3 &local2,
+ const MT_Vector3 &normal,
+ MT_Scalar dist,
+ const MT_Vector3 &rel_vel,
+ MT_Scalar restitution,
+ MT_Scalar friction_factor,
+ MT_Scalar invMass
+ );
+
+ typedef std::vector<SM_Callback *> T_CallbackList;
+
+
+ T_CallbackList m_callbackList; // Each object can have multiple callbacks from the client (=game engine)
+ SM_Object *m_dynamicParent; // Collisions between parent and children are ignored
+
+ // as the collision callback now has only information
+ // on an SM_Object, there must be a way that the SM_Object client
+ // can identify it's clientdata after a collision
+ SM_ClientObject *m_client_object;
+
+ void* m_physicsClientObject;
+
+ DT_ShapeHandle m_shape; // Shape for collision detection
+
+ // Material and shape properties are not owned by this class.
+
+ const SM_MaterialProps *m_materialProps;
+ const SM_MaterialProps *m_materialPropsBackup; // Backup in case the object temporarily becomes a ghost.
+ const SM_ShapeProps *m_shapeProps;
+ const SM_ShapeProps *m_shapePropsBackup; // Backup in case the object's dynamics is temporarily suspended
+ DT_ObjectHandle m_object; // A handle to the corresponding object in SOLID.
+ MT_Scalar m_margin; // Offset for the object's shape (also for collision detection)
+ MT_Vector3 m_scaling; // Non-uniform scaling of the object's shape
+
+ double m_ogl_matrix[16]; // An OpenGL-type 4x4 matrix
+ MT_Transform m_xform; // The object's local coordinate system
+ MT_Transform m_prev_xform; // The object's local coordinate system in the previous frame
+ SM_MotionState m_prev_state; // The object's motion state in the previous frame
+ MT_Scalar m_timeStep; // The duration of the last frame
+
+ MT_Vector3 m_reaction_impulse; // The accumulated impulse resulting from collisions
+ MT_Vector3 m_reaction_force; // The reaction force derived from the reaction impulse
+
+ MT_Vector3 m_lin_mom; // Linear momentum (linear velocity times mass)
+ MT_Vector3 m_ang_mom; // Angular momentum (angualr velocity times inertia)
+ MT_Vector3 m_force; // Force on center of mass (afffects linear momentum)
+ MT_Vector3 m_torque; // Torque around center of mass (affects angular momentum)
+
+ SM_MotionState m_frames[3];
+
+ MT_Vector3 m_error; // Error in position:- amount object must be moved to prevent intersection with scene
+
+ // Here are the values of externally set linear and angular
+ // velocity. These are updated from the outside
+ // (actuators and python) each frame and combined with the
+ // physics values. At the end of each frame (at the end of a
+ // call to proceed) they are set to zero. This allows the
+ // outside world to contribute to the velocity of an object
+ // but still have it react to physics.
+
+ MT_Vector3 m_combined_lin_vel;
+ MT_Vector3 m_combined_ang_vel;
+
+ // The force and torque are the accumulated forces and torques applied by the client (game logic, python).
+
+ SM_FhObject *m_fh_object; // The ray object used for Fh
+ bool m_suspended; // Is this object frozen?
+
+ // Mass properties
+ MT_Scalar m_inv_mass; // 1/mass
+ MT_Vector3 m_inv_inertia; // [1/inertia_x, 1/inertia_y, 1/inertia_z]
+ MT_Matrix3x3 m_inv_inertia_tensor; // Inverse Inertia Tensor
+
+ bool m_kinematic; // Have I been displaced (translated, rotated, scaled) in this frame?
+ bool m_prev_kinematic; // Have I been displaced (translated, rotated, scaled) in the previous frame?
+ bool m_is_rigid_body; // Should friction give me a change in angular momentum?
+ int m_static; // temporarily static.
+
+};
+
+#endif
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Props.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Props.h
new file mode 100644
index 00000000000..fb3f13c7b96
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Props.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 SM_PROPSH
+#define SM_PROPSH
+
+#include <MT_Scalar.h>
+
+// Properties of dynamic objects
+struct SM_ShapeProps {
+ MT_Scalar m_mass; // Total mass
+ MT_Scalar m_inertia; // Inertia, should be a tensor some time
+ MT_Scalar m_lin_drag; // Linear drag (air, water) 0 = concrete, 1 = vacuum
+ MT_Scalar m_ang_drag; // Angular drag
+ MT_Scalar m_friction_scaling[3]; // Scaling for anisotropic friction. Component in range [0, 1]
+ bool m_do_anisotropic; // Should I do anisotropic friction?
+ bool m_do_fh; // Should the object have a linear Fh spring?
+ bool m_do_rot_fh; // Should the object have an angular Fh spring?
+};
+
+
+// Properties of collidable objects (non-ghost objects)
+struct SM_MaterialProps {
+ MT_Scalar m_restitution; // restitution of energie after a collision 0 = inelastic, 1 = elastic
+ MT_Scalar m_friction; // Coulomb friction (= ratio between the normal en maximum friction force)
+ MT_Scalar m_fh_spring; // Spring constant (both linear and angular)
+ MT_Scalar m_fh_damping; // Damping factor (linear and angular) in range [0, 1]
+ MT_Scalar m_fh_distance; // The range above the surface where Fh is active.
+ bool m_fh_normal; // Should the object slide off slopes?
+};
+
+#endif //SM_PROPSH
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Scene.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Scene.h
new file mode 100644
index 00000000000..a0d5c983031
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Scene.h
@@ -0,0 +1,175 @@
+/**
+ * $Id$
+ * Copyright (C) 2001 NaN Technologies B.V.
+ * The physics scene.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 SM_SCENE_H
+#define SM_SCENE_H
+
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif
+
+#include <vector>
+#include <set>
+#include <utility> //needed for pair
+
+#include <SOLID/SOLID.h>
+
+#include "MT_Vector3.h"
+#include "MT_Point3.h"
+
+#include "SM_Object.h"
+
+typedef enum
+{
+ FH_RESPONSE,
+ SENSOR_RESPONSE, /* Touch Sensors */
+ CAMERA_RESPONSE, /* Visibility Culling */
+ OBJECT_RESPONSE, /* Object Dynamic Geometry Response */
+ STATIC_RESPONSE, /* Static Geometry Response */
+
+ NUM_RESPONSE
+};
+
+class SM_Scene {
+public:
+ SM_Scene();
+
+ ~SM_Scene();
+
+ DT_RespTableHandle getRespTableHandle() const {
+ return m_respTable;
+ }
+
+ const MT_Vector3& getForceField() const {
+ return m_forceField;
+ }
+
+ MT_Vector3& getForceField() {
+ return m_forceField;
+ }
+
+ void setForceField(const MT_Vector3& forceField) {
+ m_forceField = forceField;
+ }
+
+ void addTouchCallback(int response_class, DT_ResponseCallback callback, void *user);
+
+ void addSensor(SM_Object& object);
+ void add(SM_Object& object);
+ void remove(SM_Object& object);
+
+ void notifyCollision(SM_Object *obj1, SM_Object *obj2);
+
+ void setSecondaryRespTable(DT_RespTableHandle secondaryRespTable);
+ DT_RespTableHandle getSecondaryRespTable() { return m_secondaryRespTable; }
+
+ void requestCollisionCallback(SM_Object &object);
+
+ void beginFrame();
+ void endFrame();
+
+ // Perform an integration step of duration 'timeStep'.
+ // 'subSampling' is the maximum duration of a substep, i.e.,
+ // The maximum time interval between two collision checks.
+ // 'subSampling' can be used to control aliasing effects
+ // (fast moving objects traversing through walls and such).
+ bool proceed(MT_Scalar curtime, MT_Scalar ticrate);
+ void proceed(MT_Scalar subStep);
+
+ /**
+ * Test whether any objects lie on the line defined by from and
+ * to. The search returns the first such bject starting at from,
+ * or NULL if there was none.
+ * @returns A reference to the object, or NULL if there was none.
+ * @param ignore_client Do not look for collisions with this
+ * object. This can be useful to avoid self-hits if
+ * starting from the location of an object.
+ * @param from The start point, in world coordinates, of the search.
+ * @param to The end point, in world coordinates, of the search.
+ * @param result A store to return the point where intersection
+ * took place (if there was an intersection).
+ * @param normal A store to return the normal of the hit object on
+ * the location of the intersection, if it took place.
+ */
+ SM_Object *rayTest(void *ignore_client,
+ const MT_Point3& from, const MT_Point3& to,
+ MT_Point3& result, MT_Vector3& normal) const;
+
+private:
+
+ // Clear the user set velocities.
+ void clearObjectCombinedVelocities();
+ // This is the callback for handling collisions of dynamic objects
+ static
+ DT_Bool
+ boing(
+ void *client_data,
+ void *object1,
+ void *object2,
+ const DT_CollData *coll_data
+ );
+
+ /** internal type */
+ typedef std::vector<SM_Object *> T_ObjectList;
+
+ /** Handle to the scene in SOLID */
+ DT_SceneHandle m_scene;
+ /** Following response table contains the callbacks for the dynmics */
+ DT_RespTableHandle m_respTable;
+ DT_ResponseClass m_ResponseClass[NUM_RESPONSE];
+ /**
+ * Following response table contains callbacks for the client (=
+ * game engine) */
+ DT_RespTableHandle m_secondaryRespTable; // Handle
+ DT_ResponseClass m_secondaryResponseClass[NUM_RESPONSE];
+
+ /**
+ * Following resposne table contains callbacks for fixing the simulation
+ * ie making sure colliding objects do not intersect.
+ */
+ DT_RespTableHandle m_fixRespTable;
+ DT_ResponseClass m_fixResponseClass[NUM_RESPONSE];
+
+ /** The acceleration from the force field */
+ MT_Vector3 m_forceField;
+
+ /**
+ * The list of objects that receive motion updates and do
+ * collision tests. */
+ T_ObjectList m_objectList;
+
+ unsigned int m_frames;
+};
+
+#endif
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/sample/Makefile b/source/gameengine/Physics/Sumo/Fuzzics/sample/Makefile
new file mode 100644
index 00000000000..672dff39028
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/sample/Makefile
@@ -0,0 +1,25 @@
+#
+# $Id$
+# Copyright (C) 2001 NaN Technologies B.V.
+
+DIR = $(OCGDIR)/sumo
+ALLTARGETS = $(OBJS) $(DIR)/$(DEBUG_DIR)particle $(DIR)/$(DEBUG_DIR)particle0
+
+include nan_compile.mk
+
+CPPFLAGS = -I../../include -I../include -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(OPENGL_HEADERS)
+
+clean::
+ @$(RM) $(DIR)/particle $(DIR)/particle0
+ @$(RM) $(DIR)/debug/particle $(DIR)/debug/particle0
+
+LDFLAGS = -L$(DIR) -L/usr/X11R6/lib
+OGL_LDLIBS = -lglut -lGLU -lGL -pthread
+LDLIBS = -lfuzzics -lsolid $(NAN_MOTO)/lib/libmoto.a $(OGL_LDLIBS)
+
+$(DIR)/$(DEBUG_DIR)particle: particle.o $(DIR)/$(DEBUG_DIR)libfuzzics.a $(DIR)/$(DEBUG_DIR)libsolid.a
+ $(CCC) $(CCFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ $(LDLIBS)
+
+$(DIR)/$(DEBUG_DIR)particle0: particle0.o $(DIR)/$(DEBUG_DIR)libfuzzics.a $(DIR)/$(DEBUG_DIR)libsolid.a
+ $(CCC) $(CCFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ $(LDLIBS)
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/sample/particle.cpp b/source/gameengine/Physics/Sumo/Fuzzics/sample/particle.cpp
new file mode 100644
index 00000000000..d7aca326b42
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/sample/particle.cpp
@@ -0,0 +1,709 @@
+//#define FAKE_IT
+#define USE_COMPLEX
+#define QUADS
+
+#include <algorithm>
+#include <new>
+#include <GL/glut.h>
+
+#include "MT_MinMax.h"
+#include "MT_Point3.h"
+#include "MT_Vector3.h"
+#include "MT_Quaternion.h"
+#include "MT_Matrix3x3.h"
+#include "MT_Transform.h"
+
+#include "SM_Object.h"
+#include "SM_FhObject.h"
+#include "SM_Scene.h"
+
+#include <SOLID/SOLID.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+const MT_Scalar bowl_curv = 0.10;
+const MT_Scalar timeStep = 0.02;
+const MT_Scalar ground_margin = 0.0;
+const MT_Scalar sphere_radius = 0.5;
+
+const MT_Vector3 gravity(0, -9.8, 0);
+
+static MT_Scalar DISTANCE = 5;
+
+static MT_Scalar ele = 0, azi = 0;
+static MT_Point3 eye(0, 0, DISTANCE);
+static MT_Point3 center(0, 0, 0);
+
+inline double irnd() { return 2 * MT_random() - 1; }
+
+static const double SCALE_BOTTOM = 0.5;
+static const double SCALE_FACTOR = 2.0;
+
+SM_ShapeProps g_shapeProps = {
+ 1.0, // mass
+ 1.0, // inertia
+ 0.1, // linear drag
+ 0.1, // angular drag
+ { 1.0, 0.0, 0.0 }, // anisotropic friction
+ false, // do anisotropic friction?
+ true, // do fh?
+ true // do rot fh?
+};
+
+SM_MaterialProps g_materialProps = {
+ 0.7, // restitution
+ 0.0, // friction
+ 10.0, // Fh spring constant
+ 1.0, // Fh damping
+ 0.5, // Fh distance
+ true // Fh leveling
+};
+
+
+void toggleIdle();
+
+
+void newRandom();
+
+void coordSystem() {
+ glDisable(GL_LIGHTING);
+ glBegin(GL_LINES);
+ glColor3f(1, 0, 0);
+ glVertex3d(0, 0, 0);
+ glVertex3d(10, 0, 0);
+ glColor3f(0, 1, 0);
+ glVertex3d(0, 0, 0);
+ glVertex3d(0, 10, 0);
+ glColor3f(0, 0, 1);
+ glVertex3d(0, 0, 0);
+ glVertex3d(0, 0, 10);
+ glEnd();
+ glEnable(GL_LIGHTING);
+}
+
+
+void display_bbox(const MT_Point3& min, const MT_Point3& max) {
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+ glColor3f(0, 1, 1);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glBegin(GL_QUAD_STRIP);
+ glVertex3d(min[0], min[1], min[2]);
+ glVertex3d(min[0], min[1], max[2]);
+ glVertex3d(max[0], min[1], min[2]);
+ glVertex3d(max[0], min[1], max[2]);
+ glVertex3d(max[0], max[1], min[2]);
+ glVertex3d(max[0], max[1], max[2]);
+ glVertex3d(min[0], max[1], min[2]);
+ glVertex3d(min[0], max[1], max[2]);
+ glVertex3d(min[0], min[1], min[2]);
+ glVertex3d(min[0], min[1], max[2]);
+ glEnd();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_DEPTH_TEST);
+}
+
+
+
+
+class GLShape {
+public:
+ virtual void paint(GLdouble *m) const = 0;
+};
+
+
+class GLSphere : public GLShape {
+ MT_Scalar radius;
+public:
+ GLSphere(MT_Scalar r) : radius(r) {}
+
+ void paint(GLdouble *m) const {
+ glPushMatrix();
+ glLoadMatrixd(m);
+ coordSystem();
+ glutSolidSphere(radius, 20, 20);
+ glPopMatrix();
+ }
+};
+
+
+class GLBox : public GLShape {
+ MT_Vector3 extent;
+public:
+ GLBox(MT_Scalar x, MT_Scalar y, MT_Scalar z) :
+ extent(x, y, z) {}
+
+ void paint(GLdouble *m) const {
+ glPushMatrix();
+ glLoadMatrixd(m);
+ coordSystem();
+ glPushMatrix();
+ glScaled(extent[0], extent[1], extent[2]);
+ glutSolidCube(1.0);
+ glPopMatrix();
+ glPopMatrix();
+ }
+};
+
+
+class GLCone : public GLShape {
+ MT_Scalar bottomRadius;
+ MT_Scalar height;
+ mutable GLuint displayList;
+
+public:
+ GLCone(MT_Scalar r, MT_Scalar h) :
+ bottomRadius(r),
+ height(h),
+ displayList(0) {}
+
+ void paint(GLdouble *m) const {
+ glPushMatrix();
+ glLoadMatrixd(m);
+ coordSystem();
+ if (displayList) glCallList(displayList);
+ else {
+ GLUquadricObj *quadObj = gluNewQuadric();
+ displayList = glGenLists(1);
+ glNewList(displayList, GL_COMPILE_AND_EXECUTE);
+ glPushMatrix();
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ glTranslatef(0.0, 0.0, -1.0);
+ gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL);
+ gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH);
+ gluCylinder(quadObj, bottomRadius, 0, height, 15, 10);
+ glPopMatrix();
+ glEndList();
+ }
+ glPopMatrix();
+ }
+};
+
+class GLCylinder : public GLShape {
+ MT_Scalar radius;
+ MT_Scalar height;
+ mutable GLuint displayList;
+
+public:
+ GLCylinder(MT_Scalar r, MT_Scalar h) :
+ radius(r),
+ height(h),
+ displayList(0) {}
+
+ void paint(GLdouble *m) const {
+ glPushMatrix();
+ glLoadMatrixd(m);
+ coordSystem();
+ if (displayList) glCallList(displayList);
+ else {
+ GLUquadricObj *quadObj = gluNewQuadric();
+ displayList = glGenLists(1);
+ glNewList(displayList, GL_COMPILE_AND_EXECUTE);
+ glPushMatrix();
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ glTranslatef(0.0, 0.0, -1.0);
+ gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL);
+ gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH);
+ gluCylinder(quadObj, radius, radius, height, 15, 10);
+ glPopMatrix ();
+ glEndList();
+ }
+ glPopMatrix();
+ }
+};
+
+class Object;
+
+class Callback : public SM_Callback {
+public:
+ Callback(Object& object) : m_object(object) {}
+
+ virtual void do_me();
+
+private:
+ Object& m_object;
+};
+
+
+class Object {
+public:
+ Object(GLShape *gl_shape, SM_Object& object) :
+ m_gl_shape(gl_shape),
+ m_object(object),
+ m_callback(*this)
+ {
+ m_object.registerCallback(m_callback);
+ }
+
+ ~Object() {}
+
+ void paint() {
+ if (m_gl_shape) {
+ m_gl_shape->paint(m);
+ // display_bbox(m_bbox.lower(), m_bbox.upper());
+ }
+ }
+
+ void print_reaction_force() const {
+ std::cout << m_object.getReactionForce() << std::endl;
+ }
+
+ MT_Vector3 getAhead() {
+ return MT_Vector3(&m[4]);
+ }
+
+ MT_Vector3 getUp() {
+ return MT_Vector3(&m[8]);
+ }
+
+ void clearMomentum() {
+ m_object.clearMomentum();
+ }
+
+ void setMargin(MT_Scalar margin) {
+ m_object.setMargin(margin);
+ }
+
+ void setScaling(const MT_Vector3& scaling) {
+ m_object.setScaling(scaling);
+ }
+
+ const MT_Point3& getPosition() {
+ return m_object.getPosition();
+ }
+
+ void setPosition(const MT_Point3& pos) {
+ m_object.setPosition(pos);
+ }
+
+ void setOrientation(const MT_Quaternion& orn) {
+ m_object.setOrientation(orn);
+ }
+
+ void applyCenterForce(const MT_Vector3& force) {
+ m_object.applyCenterForce(force);
+ }
+
+ void applyTorque(const MT_Vector3& torque) {
+ m_object.applyTorque(torque);
+ }
+
+ MT_Point3 getWorldCoord(const MT_Point3& local) const {
+ return m_object.getWorldCoord(local);
+ }
+
+ MT_Vector3 getLinearVelocity() const {
+ return m_object.getLinearVelocity();
+ }
+
+ MT_Vector3 getAngularVelocity() const {
+ return m_object.getAngularVelocity();
+ }
+
+ void setMatrix() {
+ m_object.calcXform();
+ m_object.getMatrix(m);
+ }
+
+ const double *getMatrix() {
+ m_object.calcXform();
+ return m_object.getMatrix();
+ }
+
+private:
+ GLShape *m_gl_shape;
+ SM_Object& m_object;
+ DT_Scalar m[16];
+ Callback m_callback;
+};
+
+
+
+const MT_Scalar SPACE_SIZE = 2;
+
+static GLSphere gl_sphere(sphere_radius);
+static GLBox gl_ground(50.0, 0.0, 50.0);
+
+
+
+#ifdef USE_COMPLEX
+
+const int GRID_SCALE = 10;
+const MT_Scalar GRID_UNIT = 25.0 / GRID_SCALE;
+
+DT_ShapeHandle createComplex() {
+ DT_ShapeHandle shape = DT_NewComplexShape();
+ for (int i0 = -GRID_SCALE; i0 != GRID_SCALE; ++i0) {
+ for (int j0 = -GRID_SCALE; j0 != GRID_SCALE; ++j0) {
+ int i1 = i0 + 1;
+ int j1 = j0 + 1;
+#ifdef QUADS
+ DT_Begin();
+ DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j0);
+ DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j1);
+ DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j1);
+ DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j0);
+ DT_End();
+#else
+ DT_Begin();
+ DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j0);
+ DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1);
+ DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1);
+ DT_End();
+
+ DT_Begin();
+ DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1);
+ DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1);
+ DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j0);
+ DT_End();
+#endif
+
+ }
+ }
+ DT_EndComplexShape();
+ return shape;
+}
+
+
+static DT_ShapeHandle ground_shape = createComplex();
+
+#else
+
+static DT_ShapeHandle ground_shape = DT_Box(50, 0, 50);
+
+#endif
+
+static SM_Object sm_ground(ground_shape, &g_materialProps, 0, 0);
+static Object ground(&gl_ground, sm_ground);
+
+static SM_Object sm_sphere(DT_Sphere(0.0), &g_materialProps, &g_shapeProps, 0);
+static Object object(&gl_sphere, sm_sphere);
+
+
+static SM_Scene g_scene;
+
+
+bool g_hit = false;
+MT_Point3 g_spot;
+MT_Vector3 g_normal;
+
+
+void Callback::do_me()
+{
+ m_object.setMatrix();
+ m_object.print_reaction_force();
+}
+
+void myinit(void) {
+
+ GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
+ GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
+ GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
+
+ /* light_position is NOT default value */
+ GLfloat light_position0[] = { 1.0, 1.0, 1.0, 0.0 };
+ GLfloat light_position1[] = { -1.0, -1.0, -1.0, 0.0 };
+
+ glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
+ glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
+ glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
+
+ glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient);
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
+ glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular);
+ glLightfv(GL_LIGHT1, GL_POSITION, light_position1);
+
+
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_LIGHT1);
+
+ glShadeModel(GL_SMOOTH);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+
+ // glEnable(GL_CULL_FACE);
+ // glCullFace(GL_BACK);
+
+ ground.setPosition(MT_Point3(0, -10, 0));
+ ground.setOrientation(MT_Quaternion(0, 0, 0, 1));
+ ground.setMatrix();
+ center.setValue(0.0, 0.0, 0.0);
+ sm_ground.setMargin(ground_margin);
+
+ g_scene.setForceField(gravity);
+ g_scene.add(sm_ground);
+
+ object.setMargin(sphere_radius);
+
+ g_scene.add(sm_sphere);
+
+
+ newRandom();
+}
+
+
+//MT_Point3 cp1, cp2;
+//bool intersection;
+
+void display(void) {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ ground.paint();
+ object.paint();
+
+ if (g_hit) {
+ glDisable(GL_LIGHTING);
+ glColor3f(1, 0, 0);
+
+ glPointSize(5);
+ glBegin(GL_POINTS);
+ glVertex3d(g_spot[0], g_spot[1], g_spot[2]);
+ glEnd();
+ glPointSize(1);
+
+ glColor3f(1, 1, 0);
+ glBegin(GL_LINES);
+ glVertex3d(g_spot[0], g_spot[1], g_spot[2]);
+ glVertex3d(g_spot[0] + g_normal[0],
+ g_spot[1] + g_normal[1],
+ g_spot[2] + g_normal[2]);
+ glEnd();
+ glEnable(GL_LIGHTING);
+ }
+
+
+
+#ifdef COLLISION
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+ glColor3f(1, 1, 0);
+ if (intersection) {
+ glPointSize(5);
+ glBegin(GL_POINTS);
+ glVertex3d(cp1[0], cp1[1], cp1[2]);
+ glEnd();
+ glPointSize(1);
+ }
+ else {
+ glBegin(GL_LINES);
+ glVertex3d(cp1[0], cp1[1], cp1[2]);
+ glVertex3d(cp2[0], cp2[1], cp2[2]);
+ glEnd();
+ }
+ glEnable(GL_LIGHTING);
+ glEnable(GL_DEPTH_TEST);
+#endif
+
+ glFlush();
+ glutSwapBuffers();
+}
+
+
+
+
+
+void newRandom() {
+ object.setPosition(MT_Point3(0, 0, 0));
+ object.setOrientation(MT_Quaternion::random());
+ object.clearMomentum();
+ object.setMatrix();
+
+ display();
+}
+
+void moveAndDisplay() {
+ g_scene.proceed(timeStep, 0.01);
+
+ display();
+ g_hit = false;
+}
+
+
+void turn_left() {
+ object.applyTorque(5.0 * object.getUp());
+}
+
+void turn_right() {
+ object.applyTorque(-5.0 * object.getUp());
+}
+
+void forward() {
+ object.applyCenterForce(10.0 * object.getAhead());
+}
+
+void backward() {
+ object.applyCenterForce(-10.0 * object.getAhead());
+}
+
+void jump() {
+ object.applyCenterForce(MT_Vector3(0.0, 200.0, 0.0));
+}
+
+
+void toggleIdle() {
+ static bool idle = true;
+ if (idle) {
+ glutIdleFunc(moveAndDisplay);
+ idle = false;
+ }
+ else {
+ glutIdleFunc(NULL);
+ idle = true;
+ }
+}
+
+
+void setCamera() {
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 200.0);
+ MT_Scalar rele = MT_radians(ele);
+ MT_Scalar razi = MT_radians(azi);
+ eye.setValue(DISTANCE * sin(razi) * cos(rele),
+ DISTANCE * sin(rele),
+ DISTANCE * cos(razi) * cos(rele));
+ gluLookAt(eye[0], eye[1], eye[2],
+ center[0], center[1], center[2],
+ 0, 1, 0);
+ glMatrixMode(GL_MODELVIEW);
+ display();
+}
+
+const MT_Scalar STEPSIZE = 5;
+
+void stepLeft() { azi -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); }
+void stepRight() { azi += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); }
+void stepFront() { ele += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); }
+void stepBack() { ele -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); }
+void zoomIn() { DISTANCE -= 1; setCamera(); }
+void zoomOut() { DISTANCE += 1; setCamera(); }
+
+
+void myReshape(int w, int h) {
+ glViewport(0, 0, w, h);
+ setCamera();
+}
+
+void myKeyboard(unsigned char key, int x, int y)
+{
+ switch (key)
+ {
+ case 'w': forward(); break;
+ case 's': backward(); break;
+ case 'a': turn_left(); break;
+ case 'd': turn_right(); break;
+ case 'e': jump(); break;
+ case 'l' : stepLeft(); break;
+ case 'r' : stepRight(); break;
+ case 'f' : stepFront(); break;
+ case 'b' : stepBack(); break;
+ case 'z' : zoomIn(); break;
+ case 'x' : zoomOut(); break;
+ case 'i' : toggleIdle(); break;
+ case ' ' : newRandom(); break;
+ default:
+// std::cout << "unused key : " << key << std::endl;
+ break;
+ }
+}
+
+void mySpecial(int key, int x, int y)
+{
+ switch (key)
+ {
+ case GLUT_KEY_LEFT : stepLeft(); break;
+ case GLUT_KEY_RIGHT : stepRight(); break;
+ case GLUT_KEY_UP : stepFront(); break;
+ case GLUT_KEY_DOWN : stepBack(); break;
+ case GLUT_KEY_PAGE_UP : zoomIn(); break;
+ case GLUT_KEY_PAGE_DOWN : zoomOut(); break;
+ case GLUT_KEY_HOME : toggleIdle(); break;
+ default:
+// std::cout << "unused (special) key : " << key << std::endl;
+ break;
+ }
+}
+
+void goodbye( void)
+{
+ g_scene.remove(sm_ground);
+ g_scene.remove(sm_sphere);
+
+ std::cout << "goodbye ..." << std::endl;
+ exit(0);
+}
+
+void menu(int choice)
+{
+
+ static int fullScreen = 0;
+ static int px, py, sx, sy;
+
+ switch(choice) {
+ case 1:
+ if (fullScreen == 1) {
+ glutPositionWindow(px,py);
+ glutReshapeWindow(sx,sy);
+ glutChangeToMenuEntry(1,"Full Screen",1);
+ fullScreen = 0;
+ } else {
+ px=glutGet((GLenum)GLUT_WINDOW_X);
+ py=glutGet((GLenum)GLUT_WINDOW_Y);
+ sx=glutGet((GLenum)GLUT_WINDOW_WIDTH);
+ sy=glutGet((GLenum)GLUT_WINDOW_HEIGHT);
+ glutFullScreen();
+ glutChangeToMenuEntry(1,"Close Full Screen",1);
+ fullScreen = 1;
+ }
+ break;
+ case 2:
+ toggleIdle();
+ break;
+ case 3:
+ goodbye();
+ break;
+ default:
+ break;
+ }
+}
+
+void createMenu()
+{
+ glutCreateMenu(menu);
+ glutAddMenuEntry("Full Screen", 1);
+ glutAddMenuEntry("Toggle Idle (Start/Stop)", 2);
+ glutAddMenuEntry("Quit", 3);
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+}
+
+int main(int argc, char **argv) {
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(500, 500);
+ glutCreateWindow("Physics demo");
+
+ myinit();
+ glutKeyboardFunc(myKeyboard);
+ glutSpecialFunc(mySpecial);
+ glutReshapeFunc(myReshape);
+ createMenu();
+ glutIdleFunc(NULL);
+
+ glutDisplayFunc(display);
+ glutMainLoop();
+ return 0;
+}
+
+
+
+
+
+
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/sample/particle0.cpp b/source/gameengine/Physics/Sumo/Fuzzics/sample/particle0.cpp
new file mode 100644
index 00000000000..cdf0a2d8f64
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/sample/particle0.cpp
@@ -0,0 +1,695 @@
+//#define FAKE_IT
+#define USE_COMPLEX
+#define QUADS
+
+#include <algorithm>
+#include <new>
+#include <GL/glut.h>
+
+#include "MT_MinMax.h"
+#include "MT_Point3.h"
+#include "MT_Vector3.h"
+#include "MT_Quaternion.h"
+#include "MT_Matrix3x3.h"
+#include "MT_Transform.h"
+
+#include "SM_Object.h"
+#include "SM_Scene.h"
+
+#include "solid.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+const MT_Scalar bowl_curv = 0.10;
+const MT_Scalar timeStep = 0.04;
+const MT_Scalar ground_margin = 0.0;
+const MT_Scalar sphere_radius = 0.5;
+
+const MT_Vector3 gravity(0, -9.8, 0);
+
+static MT_Scalar DISTANCE = 5;
+
+static MT_Scalar ele = 0, azi = 0;
+static MT_Point3 eye(0, 0, DISTANCE);
+static MT_Point3 center(0, 0, 0);
+
+inline double irnd() { return 2 * MT_random() - 1; }
+
+static const double SCALE_BOTTOM = 0.5;
+static const double SCALE_FACTOR = 2.0;
+
+SM_ShapeProps g_shapeProps = {
+ 1.0, // mass
+ 1.0, // inertia
+ 0.9, // linear drag
+ 0.9 // angular drag
+};
+
+SM_MaterialProps g_materialProps = {
+ 0.7, // restitution
+ 0.0, // friction
+ 0.0, // spring constant
+ 0.0 // damping
+};
+
+
+void toggleIdle();
+
+
+void newRandom();
+
+void coordSystem() {
+ glDisable(GL_LIGHTING);
+ glBegin(GL_LINES);
+ glColor3f(1, 0, 0);
+ glVertex3d(0, 0, 0);
+ glVertex3d(10, 0, 0);
+ glColor3f(0, 1, 0);
+ glVertex3d(0, 0, 0);
+ glVertex3d(0, 10, 0);
+ glColor3f(0, 0, 1);
+ glVertex3d(0, 0, 0);
+ glVertex3d(0, 0, 10);
+ glEnd();
+ glEnable(GL_LIGHTING);
+}
+
+
+void display_bbox(const MT_Point3& min, const MT_Point3& max) {
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+ glColor3f(0, 1, 1);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glBegin(GL_QUAD_STRIP);
+ glVertex3d(min[0], min[1], min[2]);
+ glVertex3d(min[0], min[1], max[2]);
+ glVertex3d(max[0], min[1], min[2]);
+ glVertex3d(max[0], min[1], max[2]);
+ glVertex3d(max[0], max[1], min[2]);
+ glVertex3d(max[0], max[1], max[2]);
+ glVertex3d(min[0], max[1], min[2]);
+ glVertex3d(min[0], max[1], max[2]);
+ glVertex3d(min[0], min[1], min[2]);
+ glVertex3d(min[0], min[1], max[2]);
+ glEnd();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_DEPTH_TEST);
+}
+
+
+
+
+class GLShape {
+public:
+ virtual void paint(GLdouble *m) const = 0;
+};
+
+
+class GLSphere : public GLShape {
+ MT_Scalar radius;
+public:
+ GLSphere(MT_Scalar r) : radius(r) {}
+
+ void paint(GLdouble *m) const {
+ glPushMatrix();
+ glLoadMatrixd(m);
+ coordSystem();
+ glutSolidSphere(radius, 20, 20);
+ glPopMatrix();
+ }
+};
+
+
+class GLBox : public GLShape {
+ MT_Vector3 extent;
+public:
+ GLBox(MT_Scalar x, MT_Scalar y, MT_Scalar z) :
+ extent(x, y, z) {}
+
+ void paint(GLdouble *m) const {
+ glPushMatrix();
+ glLoadMatrixd(m);
+ coordSystem();
+ glPushMatrix();
+ glScaled(extent[0], extent[1], extent[2]);
+ glutSolidCube(1.0);
+ glPopMatrix();
+ glPopMatrix();
+ }
+};
+
+
+class GLCone : public GLShape {
+ MT_Scalar bottomRadius;
+ MT_Scalar height;
+ mutable GLuint displayList;
+
+public:
+ GLCone(MT_Scalar r, MT_Scalar h) :
+ bottomRadius(r),
+ height(h),
+ displayList(0) {}
+
+ void paint(GLdouble *m) const {
+ glPushMatrix();
+ glLoadMatrixd(m);
+ coordSystem();
+ if (displayList) glCallList(displayList);
+ else {
+ GLUquadricObj *quadObj = gluNewQuadric();
+ displayList = glGenLists(1);
+ glNewList(displayList, GL_COMPILE_AND_EXECUTE);
+ glPushMatrix();
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ glTranslatef(0.0, 0.0, -1.0);
+ gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL);
+ gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH);
+ gluCylinder(quadObj, bottomRadius, 0, height, 15, 10);
+ glPopMatrix();
+ glEndList();
+ }
+ glPopMatrix();
+ }
+};
+
+class GLCylinder : public GLShape {
+ MT_Scalar radius;
+ MT_Scalar height;
+ mutable GLuint displayList;
+
+public:
+ GLCylinder(MT_Scalar r, MT_Scalar h) :
+ radius(r),
+ height(h),
+ displayList(0) {}
+
+ void paint(GLdouble *m) const {
+ glPushMatrix();
+ glLoadMatrixd(m);
+ coordSystem();
+ if (displayList) glCallList(displayList);
+ else {
+ GLUquadricObj *quadObj = gluNewQuadric();
+ displayList = glGenLists(1);
+ glNewList(displayList, GL_COMPILE_AND_EXECUTE);
+ glPushMatrix();
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ glTranslatef(0.0, 0.0, -1.0);
+ gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL);
+ gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH);
+ gluCylinder(quadObj, radius, radius, height, 15, 10);
+ glPopMatrix ();
+ glEndList();
+ }
+ glPopMatrix();
+ }
+};
+
+class Object;
+
+class Callback : public SM_Callback {
+public:
+ Callback(Object& object) : m_object(object) {}
+
+ virtual void do_me();
+
+private:
+ Object& m_object;
+};
+
+
+class Object {
+public:
+ Object(GLShape *gl_shape, SM_Object& object) :
+ m_gl_shape(gl_shape),
+ m_object(object),
+ m_callback(*this)
+ {
+ m_object.registerCallback(m_callback);
+ }
+
+ ~Object() {}
+
+ void paint() {
+ m_gl_shape->paint(m);
+ // display_bbox(m_bbox.lower(), m_bbox.upper());
+ }
+
+ MT_Vector3 getAhead() {
+ return MT_Vector3(-m[8], -m[9], -m[10]);
+ }
+
+ void clearMomentum() {
+ m_object.clearMomentum();
+ }
+
+ void setMargin(MT_Scalar margin) {
+ m_object.setMargin(margin);
+ }
+
+ void setScaling(const MT_Vector3& scaling) {
+ m_object.setScaling(scaling);
+ }
+
+ void setPosition(const MT_Point3& pos) {
+ m_object.setPosition(pos);
+ }
+
+ void setOrientation(const MT_Quaternion& orn) {
+ m_object.setOrientation(orn);
+ }
+
+ void applyCenterForce(const MT_Vector3& force) {
+ m_object.applyCenterForce(force);
+ }
+
+ void applyTorque(const MT_Vector3& torque) {
+ m_object.applyTorque(torque);
+ }
+
+ MT_Point3 getWorldCoord(const MT_Point3& local) const {
+ return m_object.getWorldCoord(local);
+ }
+
+ MT_Vector3 getLinearVelocity() const {
+ return m_object.getLinearVelocity();
+ }
+
+ void setMatrix() {
+ m_object.getMatrix(m);
+ }
+
+private:
+ GLShape *m_gl_shape;
+ SM_Object& m_object;
+ DT_Scalar m[16];
+ Callback m_callback;
+};
+
+
+void Callback::do_me()
+{
+ m_object.setMatrix();
+}
+
+
+const MT_Scalar SPACE_SIZE = 2;
+
+static GLSphere gl_sphere(sphere_radius);
+static GLBox gl_ground(50.0, 0.0, 50.0);
+
+
+
+#ifdef USE_COMPLEX
+
+const int GRID_SCALE = 10;
+const MT_Scalar GRID_UNIT = 25.0 / GRID_SCALE;
+
+DT_ShapeHandle createComplex() {
+ DT_ShapeHandle shape = DT_NewComplexShape();
+ for (int i0 = -GRID_SCALE; i0 != GRID_SCALE; ++i0) {
+ for (int j0 = -GRID_SCALE; j0 != GRID_SCALE; ++j0) {
+ int i1 = i0 + 1;
+ int j1 = j0 + 1;
+#ifdef QUADS
+ DT_Begin();
+ DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j0);
+ DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j1);
+ DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j1);
+ DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j0);
+ DT_End();
+#else
+ DT_Begin();
+ DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j0);
+ DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1);
+ DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1);
+ DT_End();
+
+ DT_Begin();
+ DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1);
+ DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1);
+ DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j0);
+ DT_End();
+#endif
+
+ }
+ }
+ DT_EndComplexShape();
+ return shape;
+}
+
+
+static DT_ShapeHandle ground_shape = createComplex();
+
+#else
+
+static DT_ShapeHandle ground_shape = DT_Box(50, 0, 50);
+
+#endif
+
+static SM_Object sm_ground(ground_shape, &g_materialProps, 0, 0);
+static Object ground(&gl_ground, sm_ground);
+
+static SM_Object sm_sphere(DT_Sphere(0.0), &g_materialProps, &g_shapeProps, 0);
+static Object object(&gl_sphere, sm_sphere);
+
+
+static SM_Object sm_ray(DT_Ray(0.0, -1.0, 0.0), 0, 0, 0);
+
+static SM_Scene g_scene;
+
+
+void myinit(void) {
+
+ GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
+ GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
+ GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
+
+ /* light_position is NOT default value */
+ GLfloat light_position0[] = { 1.0, 1.0, 1.0, 0.0 };
+ GLfloat light_position1[] = { -1.0, -1.0, -1.0, 0.0 };
+
+ glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
+ glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
+ glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
+
+ glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient);
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
+ glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular);
+ glLightfv(GL_LIGHT1, GL_POSITION, light_position1);
+
+
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_LIGHT1);
+
+ glShadeModel(GL_SMOOTH);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+
+ // glEnable(GL_CULL_FACE);
+ // glCullFace(GL_BACK);
+
+ g_scene.setForceField(gravity);
+ g_scene.add(sm_ground);
+ sm_ground.setMargin(ground_margin);
+
+ new(&object) Object(&gl_sphere, sm_sphere);
+
+
+ object.setMargin(sphere_radius);
+
+ g_scene.add(sm_sphere);
+
+ ground.setPosition(MT_Point3(0, -10, 0));
+ ground.setOrientation(MT_Quaternion(0, 0, 0, 1));
+ ground.setMatrix();
+ center.setValue(0.0, 0.0, 0.0);
+
+ newRandom();
+}
+
+
+//MT_Point3 cp1, cp2;
+//bool intersection;
+
+bool g_hit = false;
+MT_Point3 g_spot;
+MT_Vector3 g_normal;
+
+
+void display(void) {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ ground.paint();
+ object.paint();
+
+ if (g_hit) {
+ glPointSize(5);
+ glBegin(GL_POINTS);
+ glVertex3d(g_spot[0], g_spot[1], g_spot[2]);
+ glEnd();
+ glPointSize(1);
+ }
+
+
+
+#ifdef COLLISION
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+ glColor3f(1, 1, 0);
+ if (intersection) {
+ glPointSize(5);
+ glBegin(GL_POINTS);
+ glVertex3d(cp1[0], cp1[1], cp1[2]);
+ glEnd();
+ glPointSize(1);
+ }
+ else {
+ glBegin(GL_LINES);
+ glVertex3d(cp1[0], cp1[1], cp1[2]);
+ glVertex3d(cp2[0], cp2[1], cp2[2]);
+ glEnd();
+ }
+ glEnable(GL_LIGHTING);
+ glEnable(GL_DEPTH_TEST);
+#endif
+
+ glFlush();
+ glutSwapBuffers();
+}
+
+
+
+
+
+void newRandom() {
+ object.setPosition(MT_Point3(0, 0, 0));
+ object.clearMomentum();
+ object.setMatrix();
+
+ display();
+}
+
+void moveAndDisplay() {
+ g_scene.proceed(timeStep, 0.01);
+
+ MT_Vector3 normal(0, 1, 0);
+
+ MT_Point3 from = object.getWorldCoord(MT_Point3(0, 0, 0));
+ MT_Point3 to = from - normal * 10.0;
+
+ g_hit = DT_ObjectRayTest(sm_ground.getObjectHandle(),
+ from.getValue(),
+ to.getValue(), g_spot.getValue(),
+ g_normal.getValue());
+
+ // Scrap
+#define DO_FH
+#ifdef DO_FH
+ MT_Scalar dist = MT_distance(from, g_spot);
+ if (dist < 5.0) {
+ MT_Vector3 lin_vel = object.getLinearVelocity();
+ MT_Scalar lin_vel_normal = lin_vel.dot(normal);
+
+ MT_Scalar spring_extent = dist + lin_vel_normal * (timeStep * 0.5);
+
+ MT_Scalar f_spring = (5.0 - spring_extent) * 3.0;
+ object.applyCenterForce(normal * f_spring);
+ object.applyCenterForce(-lin_vel_normal * normal);
+ }
+
+#endif
+
+
+ display();
+}
+
+
+void turn_left() {
+ object.applyTorque(MT_Vector3(0.0, 10.0, 0.0));
+}
+
+void turn_right() {
+ object.applyTorque(MT_Vector3(0.0, -10.0, 0.0));
+}
+
+void forward() {
+ object.applyCenterForce(20.0 * object.getAhead());
+}
+
+void backward() {
+ object.applyCenterForce(-20.0 * object.getAhead());
+}
+
+void jump() {
+ object.applyCenterForce(MT_Vector3(0.0, 200.0, 0.0));
+}
+
+
+void toggleIdle() {
+ static bool idle = true;
+ if (idle) {
+ glutIdleFunc(moveAndDisplay);
+ idle = false;
+ }
+ else {
+ glutIdleFunc(NULL);
+ idle = true;
+ }
+}
+
+
+void setCamera() {
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 200.0);
+ MT_Scalar rele = MT_radians(ele);
+ MT_Scalar razi = MT_radians(azi);
+ eye.setValue(DISTANCE * sin(razi) * cos(rele),
+ DISTANCE * sin(rele),
+ DISTANCE * cos(razi) * cos(rele));
+ gluLookAt(eye[0], eye[1], eye[2],
+ center[0], center[1], center[2],
+ 0, 1, 0);
+ glMatrixMode(GL_MODELVIEW);
+ display();
+}
+
+const MT_Scalar STEPSIZE = 5;
+
+void stepLeft() { azi -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); }
+void stepRight() { azi += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); }
+void stepFront() { ele += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); }
+void stepBack() { ele -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); }
+void zoomIn() { DISTANCE -= 1; setCamera(); }
+void zoomOut() { DISTANCE += 1; setCamera(); }
+
+
+void myReshape(int w, int h) {
+ glViewport(0, 0, w, h);
+ setCamera();
+}
+
+void myKeyboard(unsigned char key, int x, int y)
+{
+ switch (key)
+ {
+ case 'w': forward(); break;
+ case 's': backward(); break;
+ case 'a': turn_left(); break;
+ case 'd': turn_right(); break;
+ case 'e': jump(); break;
+ case 'l' : stepLeft(); break;
+ case 'r' : stepRight(); break;
+ case 'f' : stepFront(); break;
+ case 'b' : stepBack(); break;
+ case 'z' : zoomIn(); break;
+ case 'x' : zoomOut(); break;
+ case 'i' : toggleIdle(); break;
+ case ' ' : newRandom(); break;
+ default:
+// std::cout << "unused key : " << key << std::endl;
+ break;
+ }
+}
+
+void mySpecial(int key, int x, int y)
+{
+ switch (key)
+ {
+ case GLUT_KEY_LEFT : stepLeft(); break;
+ case GLUT_KEY_RIGHT : stepRight(); break;
+ case GLUT_KEY_UP : stepFront(); break;
+ case GLUT_KEY_DOWN : stepBack(); break;
+ case GLUT_KEY_PAGE_UP : zoomIn(); break;
+ case GLUT_KEY_PAGE_DOWN : zoomOut(); break;
+ case GLUT_KEY_HOME : toggleIdle(); break;
+ default:
+// std::cout << "unused (special) key : " << key << std::endl;
+ break;
+ }
+}
+
+void goodbye( void)
+{
+ g_scene.remove(sm_ground);
+ g_scene.remove(sm_sphere);
+
+ std::cout << "goodbye ..." << std::endl;
+ exit(0);
+}
+
+void menu(int choice)
+{
+
+ static int fullScreen = 0;
+ static int px, py, sx, sy;
+
+ switch(choice) {
+ case 1:
+ if (fullScreen == 1) {
+ glutPositionWindow(px,py);
+ glutReshapeWindow(sx,sy);
+ glutChangeToMenuEntry(1,"Full Screen",1);
+ fullScreen = 0;
+ } else {
+ px=glutGet((GLenum)GLUT_WINDOW_X);
+ py=glutGet((GLenum)GLUT_WINDOW_Y);
+ sx=glutGet((GLenum)GLUT_WINDOW_WIDTH);
+ sy=glutGet((GLenum)GLUT_WINDOW_HEIGHT);
+ glutFullScreen();
+ glutChangeToMenuEntry(1,"Close Full Screen",1);
+ fullScreen = 1;
+ }
+ break;
+ case 2:
+ toggleIdle();
+ break;
+ case 3:
+ goodbye();
+ break;
+ default:
+ break;
+ }
+}
+
+void createMenu()
+{
+ glutCreateMenu(menu);
+ glutAddMenuEntry("Full Screen", 1);
+ glutAddMenuEntry("Toggle Idle (Start/Stop)", 2);
+ glutAddMenuEntry("Quit", 3);
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+}
+
+int main(int argc, char **argv) {
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(500, 500);
+ glutCreateWindow("Physics demo");
+
+ myinit();
+ glutKeyboardFunc(myKeyboard);
+ glutSpecialFunc(mySpecial);
+ glutReshapeFunc(myReshape);
+ createMenu();
+ glutIdleFunc(NULL);
+
+ glutDisplayFunc(display);
+ glutMainLoop();
+ return 0;
+}
+
+
+
+
+
+
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/Makefile b/source/gameengine/Physics/Sumo/Fuzzics/src/Makefile
new file mode 100644
index 00000000000..b2744c5496a
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/src/Makefile
@@ -0,0 +1,14 @@
+#
+# $Id$
+# Copyright (C) 2001 NaN Technologies B.V.
+
+LIBNAME = fuzzics
+DIR = $(OCGDIR)/gameengine/blphys/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../include -I$(NAN_MOTO)/include -I../../include
+CPPFLAGS += -I$(NAN_SOLID)/include
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_FhObject.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_FhObject.cpp
new file mode 100644
index 00000000000..e905459ce21
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_FhObject.cpp
@@ -0,0 +1,183 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SM_FhObject.h"
+#include "MT_MinMax.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+SM_FhObject::SM_FhObject(DT_ShapeHandle rayshape, MT_Vector3 ray, SM_Object *parent_object) :
+ SM_Object(rayshape, NULL, NULL, NULL),
+ m_ray(ray),
+ m_ray_direction(ray.normalized()),
+ m_parent_object(parent_object)
+{
+}
+
+SM_FhObject::~SM_FhObject()
+{
+ DT_DeleteShape(getShapeHandle());
+}
+
+DT_Bool SM_FhObject::ray_hit(void *client_data,
+ void *client_object1,
+ void *client_object2,
+ const DT_CollData *coll_data)
+{
+
+ SM_FhObject *fh_object = dynamic_cast<SM_FhObject *>((SM_Object *)client_object2);
+ if (!fh_object)
+ {
+ std::swap(client_object1, client_object2);
+ fh_object = dynamic_cast<SM_FhObject *>((SM_Object *)client_object2);
+ }
+
+ SM_Object *hit_object = (SM_Object *)client_object1;
+ const SM_MaterialProps *matProps = hit_object->getMaterialProps();
+
+ if ((matProps == 0) || (matProps->m_fh_distance < MT_EPSILON)) {
+ return DT_CONTINUE;
+ }
+
+ SM_Object *cl_object = fh_object->getParentObject();
+
+ assert(fh_object);
+
+ if (hit_object == cl_object) {
+ // Shot myself in the foot...
+ return DT_CONTINUE;
+ }
+
+ const SM_ShapeProps *shapeProps = cl_object->getShapeProps();
+
+ // Exit if the client object is not dynamic.
+ if (shapeProps == 0) {
+ return DT_CONTINUE;
+ }
+
+ MT_Point3 lspot;
+ MT_Vector3 normal;
+
+ DT_Vector3 from, to, dnormal;
+ DT_Scalar dlspot;
+ fh_object->getPosition().getValue(from);
+ fh_object->getSpot().getValue(to);
+
+
+ if (DT_ObjectRayCast(hit_object->getObjectHandle(),
+ from,
+ to,
+ 1.,
+ &dlspot,
+ dnormal)) {
+
+ lspot = fh_object->getPosition() + (fh_object->getSpot() - fh_object->getPosition()) * dlspot;
+ const MT_Vector3& ray_dir = fh_object->getRayDirection();
+ MT_Scalar dist = MT_distance(fh_object->getPosition(), lspot) -
+ cl_object->getMargin() - shapeProps->m_radius;
+
+ normal = MT_Vector3(dnormal).safe_normalized();
+
+ if (dist < matProps->m_fh_distance) {
+
+ if (shapeProps->m_do_fh) {
+ lspot -= hit_object->getPosition();
+ MT_Vector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocity(lspot);
+ MT_Scalar rel_vel_ray = ray_dir.dot(rel_vel);
+ MT_Scalar spring_extent = 1.0 - dist / matProps->m_fh_distance;
+
+ MT_Scalar i_spring = spring_extent * matProps->m_fh_spring;
+ MT_Scalar i_damp = rel_vel_ray * matProps->m_fh_damping;
+
+ cl_object->addLinearVelocity(-(i_spring + i_damp) * ray_dir);
+ if (matProps->m_fh_normal) {
+ cl_object->addLinearVelocity(
+ (i_spring + i_damp) *
+ (normal - normal.dot(ray_dir) * ray_dir));
+ }
+
+ MT_Vector3 lateral = rel_vel - rel_vel_ray * ray_dir;
+ const SM_ShapeProps *shapeProps = cl_object->getShapeProps();
+
+ if (shapeProps->m_do_anisotropic) {
+ MT_Matrix3x3 lcs(cl_object->getOrientation());
+ MT_Vector3 loc_lateral = lateral * lcs;
+ const MT_Vector3& friction_scaling =
+ shapeProps->m_friction_scaling;
+
+ loc_lateral.scale(friction_scaling[0],
+ friction_scaling[1],
+ friction_scaling[2]);
+ lateral = lcs * loc_lateral;
+ }
+
+
+ MT_Scalar rel_vel_lateral = lateral.length();
+
+ if (rel_vel_lateral > MT_EPSILON) {
+ MT_Scalar friction_factor = matProps->m_friction;
+ MT_Scalar max_friction = friction_factor * MT_max(MT_Scalar(0.0), i_spring);
+
+ MT_Scalar rel_mom_lateral = rel_vel_lateral /
+ cl_object->getInvMass();
+
+ MT_Vector3 friction =
+ (rel_mom_lateral > max_friction) ?
+ -lateral * (max_friction / rel_vel_lateral) :
+ -lateral;
+
+ cl_object->applyCenterImpulse(friction);
+ }
+ }
+
+ if (shapeProps->m_do_rot_fh) {
+ const double *ogl_mat = cl_object->getMatrix();
+ MT_Vector3 up(&ogl_mat[8]);
+ MT_Vector3 t_spring = up.cross(normal) * matProps->m_fh_spring;
+ MT_Vector3 ang_vel = cl_object->getAngularVelocity();
+
+ // only rotations that tilt relative to the normal are damped
+ ang_vel -= ang_vel.dot(normal) * normal;
+
+ MT_Vector3 t_damp = ang_vel * matProps->m_fh_damping;
+
+ cl_object->addAngularVelocity(t_spring - t_damp);
+ }
+ }
+ }
+
+ return DT_CONTINUE;
+}
+
+
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_MotionState.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_MotionState.cpp
new file mode 100644
index 00000000000..1fadbdadfa0
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_MotionState.cpp
@@ -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 *****
+ */
+#include <MT_Scalar.h>
+#include <MT_Vector3.h>
+#include <MT_Quaternion.h>
+
+#include "SM_MotionState.h"
+
+void SM_MotionState::integrateMidpoint(MT_Scalar timeStep, const SM_MotionState &prev_state, const MT_Vector3 &velocity, const MT_Quaternion& ang_vel)
+{
+ m_pos += (prev_state.getLinearVelocity() + velocity) * (timeStep * 0.5);
+ m_orn += (prev_state.getAngularVelocity() * prev_state.getOrientation() + ang_vel * m_orn) * (timeStep * 0.25);
+ m_orn.normalize();
+}
+
+void SM_MotionState::integrateBackward(MT_Scalar timeStep, const MT_Vector3 &velocity, const MT_Quaternion& ang_vel)
+{
+ m_pos += velocity * timeStep;
+ m_orn += ang_vel * m_orn * (timeStep * 0.5);
+ m_orn.normalize();
+}
+
+void SM_MotionState::integrateForward(MT_Scalar timeStep, const SM_MotionState &prev_state)
+{
+ m_pos += prev_state.getLinearVelocity() * timeStep;
+ m_orn += prev_state.getAngularVelocity() * m_orn * (timeStep * 0.5);
+ m_orn.normalize();
+}
+
+/*
+// Newtonian lerp: interpolate based on Newtonian motion
+void SM_MotionState::nlerp(const SM_MotionState &prev, const SM_MotionState &next)
+{
+ MT_Scalar dt = next.getTime() - prev.getTime();
+ MT_Scalar t = getTime() - prev.getTime();
+ MT_Vector3 dx = next.getPosition() - prev.getPosition();
+ MT_Vector3 a = dx/(dt*dt) - prev.getLinearVelocity()/dt;
+
+ m_pos = prev.getPosition() + prev.getLinearVelocity()*t + a*t*t;
+}
+*/
+
+void SM_MotionState::lerp(const SM_MotionState &prev, const SM_MotionState &next)
+{
+ MT_Scalar dt = next.getTime() - prev.getTime();
+ if (MT_fuzzyZero(dt))
+ {
+ *this = next;
+ return;
+ }
+
+ MT_Scalar x = (getTime() - prev.getTime())/dt;
+
+ m_pos = x*next.getPosition() + (1-x)*prev.getPosition();
+
+ m_orn = prev.getOrientation().slerp(next.getOrientation(), 1-x);
+
+ m_lin_vel = x*next.getLinearVelocity() + (1-x)*prev.getLinearVelocity();
+ m_ang_vel = x*next.getAngularVelocity() + (1-x)*prev.getAngularVelocity();
+}
+
+void SM_MotionState::lerp(MT_Scalar t, const SM_MotionState &other)
+{
+ MT_Scalar x = (t - getTime())/(other.getTime() - getTime());
+ m_pos = (1-x)*m_pos + x*other.getPosition();
+
+ m_orn = other.getOrientation().slerp(m_orn, x);
+
+ m_lin_vel = (1-x)*m_lin_vel + x*other.getLinearVelocity();
+ m_ang_vel = (1-x)*m_ang_vel + x*other.getAngularVelocity();
+
+ m_time = t;
+}
+
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Object.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Object.cpp
new file mode 100644
index 00000000000..c8a191cad0d
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Object.cpp
@@ -0,0 +1,1301 @@
+/**
+ * $Id$
+ * Copyright (C) 2001 NaN Technologies B.V.
+ * The basic physics object.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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
+// This warning tells us about truncation of __long__ stl-generated names.
+// It can occasionally cause DevStudio to have internal compiler warnings.
+#pragma warning( disable : 4786 )
+#endif
+
+#include "MT_assert.h"
+
+#include "SM_Object.h"
+#include "SM_Scene.h"
+#include "SM_FhObject.h"
+#include "SM_Debug.h"
+
+#include "MT_MinMax.h"
+
+MT_Scalar SM_Object::ImpulseThreshold = -1.0;
+
+struct Contact
+{
+ SM_Object *obj1;
+ SM_Object *obj2;
+ MT_Vector3 normal;
+ MT_Point3 pos;
+
+ // Sort objects by height
+ bool operator()(const Contact *a, const Contact *b)
+ {
+ return a->pos[2] < b->pos[2];
+ }
+
+ Contact(SM_Object *o1, SM_Object *o2, const MT_Vector3 nor, const MT_Point3 p)
+ : obj1(o1),
+ obj2(o2),
+ normal(nor),
+ pos(p)
+ {
+ }
+
+ Contact()
+ {
+ }
+
+ void resolve()
+ {
+ if (obj1->m_static || obj2->m_static)
+ {
+ if (obj1->isDynamic())
+ {
+ if (obj1->m_static && obj2->m_static)
+ {
+ if (obj1->m_static < obj2->m_static)
+ {
+ obj2->m_error -= normal;
+ obj2->m_static = obj1->m_static + 1;
+ }
+ else
+ {
+ obj1->m_error += normal;
+ obj1->m_static = obj2->m_static + 1;
+ }
+ }
+ else
+ {
+ if (obj1->m_static)
+ {
+ obj2->m_error -= normal;
+ obj2->m_static = obj1->m_static + 1;
+ }
+ else
+ {
+ obj1->m_error += normal;
+ obj1->m_static = obj2->m_static + 1;
+ }
+ }
+ }
+ else
+ {
+ obj2->m_error -= normal;
+ obj2->m_static = 1;
+ }
+ }
+ else
+ {
+ // This distinction between dynamic and non-dynamic objects should not be
+ // necessary. Non-dynamic objects are assumed to have infinite mass.
+ if (obj1->isDynamic()) {
+ MT_Vector3 error = normal * 0.5f;
+ obj1->m_error += error;
+ obj2->m_error -= error;
+ }
+ else {
+ // Same again but now obj1 is non-dynamic
+ obj2->m_error -= normal;
+ obj2->m_static = obj1->m_static + 1;
+ }
+ }
+
+ }
+
+
+ typedef std::set<Contact*, Contact> Set;
+};
+
+static Contact::Set contacts;
+
+SM_Object::SM_Object(
+ DT_ShapeHandle shape,
+ const SM_MaterialProps *materialProps,
+ const SM_ShapeProps *shapeProps,
+ SM_Object *dynamicParent) :
+
+ m_dynamicParent(dynamicParent),
+ m_client_object(0),
+ m_physicsClientObject(0),
+ m_shape(shape),
+ m_materialProps(materialProps),
+ m_materialPropsBackup(0),
+ m_shapeProps(shapeProps),
+ m_shapePropsBackup(0),
+ m_margin(0.0),
+ m_scaling(1.0, 1.0, 1.0),
+ m_reaction_impulse(0.0, 0.0, 0.0),
+ m_reaction_force(0.0, 0.0, 0.0),
+ m_lin_mom(0.0, 0.0, 0.0),
+ m_ang_mom(0.0, 0.0, 0.0),
+ m_force(0.0, 0.0, 0.0),
+ m_torque(0.0, 0.0, 0.0),
+ m_error(0.0, 0.0, 0.0),
+ m_combined_lin_vel (0.0, 0.0, 0.0),
+ m_combined_ang_vel (0.0, 0.0, 0.0),
+ m_fh_object(0),
+ m_inv_mass(0.0),
+ m_inv_inertia(0., 0., 0.),
+ m_kinematic(false),
+ m_prev_kinematic(false),
+ m_is_rigid_body(false),
+ m_static(0)
+{
+ m_object = DT_CreateObject(this, shape);
+ m_xform.setIdentity();
+ m_xform.getValue(m_ogl_matrix);
+ if (shapeProps)
+ {
+ if (shapeProps->m_do_fh || shapeProps->m_do_rot_fh)
+ {
+ DT_Vector3 zero = {0., 0., 0.}, ray = {0.0, 0.0, -10.0};
+ m_fh_object = new SM_FhObject(DT_NewLineSegment(zero, ray), MT_Vector3(ray), this);
+ //printf("SM_Object:: WARNING! fh disabled.\n");
+ }
+ m_inv_mass = 1. / shapeProps->m_mass;
+ m_inv_inertia = MT_Vector3(1./shapeProps->m_inertia[0], 1./shapeProps->m_inertia[1], 1./shapeProps->m_inertia[2]);
+ }
+ updateInvInertiaTensor();
+ m_suspended = false;
+}
+
+
+ void
+SM_Object::
+integrateForces(
+ MT_Scalar timeStep
+){
+ if (!m_suspended) {
+ m_prev_state = getNextFrame();
+ m_prev_state.setLinearVelocity(actualLinVelocity());
+ m_prev_state.setAngularVelocity(actualAngVelocity());
+ if (isDynamic()) {
+ // Integrate momentum (forward Euler)
+ m_lin_mom += m_force * timeStep;
+ m_ang_mom += m_torque * timeStep;
+ // Drain momentum because of air/water resistance
+ m_lin_mom *= pow(m_shapeProps->m_lin_drag, timeStep);
+ m_ang_mom *= pow(m_shapeProps->m_ang_drag, timeStep);
+ // Set velocities according momentum
+ getNextFrame().setLinearVelocity(m_lin_mom * m_inv_mass);
+ getNextFrame().setAngularVelocity(m_inv_inertia_tensor * m_ang_mom);
+ }
+ }
+
+};
+
+ void
+SM_Object::
+integrateMomentum(
+ MT_Scalar timeStep
+){
+ // Integrate position and orientation
+
+ // only do it for objects with linear and/or angular velocity
+ // else clients with hierarchies may get into trouble
+ if (!actualLinVelocity().fuzzyZero() || !actualAngVelocity().fuzzyZero())
+ {
+
+ // those MIDPOINT and BACKWARD integration methods are
+ // in this form not ok with some testfiles !
+ // For a release build please use forward euler unless completely tested
+
+//#define MIDPOINT
+//#define BACKWARD
+#ifdef MIDPOINT
+// Midpoint rule
+ getNextFrame().integrateMidpoint(timeStep, m_prev_state, actualLinVelocity(), actualAngVelocity());
+#elif defined BACKWARD
+// Backward Euler
+ getNextFrame().integrateBackward(timeStep, actualLinVelocity(), actualAngVelocity());
+#else
+// Forward Euler
+ getNextFrame().integrateForward(timeStep, m_prev_state);
+#endif
+
+ calcXform();
+ notifyClient();
+
+ }
+}
+
+/**
+ * dynamicCollision computes the response to a collision.
+ *
+ * @param local2 the contact point in local coordinates.
+ * @param normal the contact normal.
+ * @param dist the penetration depth of the contact. (unused)
+ * @param rel_vel the relative velocity of the objects
+ * @param restitution the amount of momentum conserved in the collision. Range: 0.0 - 1.0
+ * @param friction_factor the amount of friction between the two surfaces.
+ * @param invMass the inverse mass of the collision objects (1.0 / mass)
+ */
+void SM_Object::dynamicCollision(const MT_Point3 &local2,
+ const MT_Vector3 &normal,
+ MT_Scalar dist,
+ const MT_Vector3 &rel_vel,
+ MT_Scalar restitution,
+ MT_Scalar friction_factor,
+ MT_Scalar invMass
+)
+{
+ /**
+ * rel_vel_normal is the relative velocity in the contact normal direction.
+ */
+ MT_Scalar rel_vel_normal = normal.dot(rel_vel);
+
+ /**
+ * if rel_vel_normal > 0, the objects are moving apart!
+ */
+ if (rel_vel_normal < -MT_EPSILON) {
+ /**
+ * if rel_vel_normal < ImpulseThreshold, scale the restitution down.
+ * This should improve the simulation where the object is stacked.
+ */
+ restitution *= MT_min(MT_Scalar(1.0), rel_vel_normal/ImpulseThreshold);
+
+ MT_Scalar impulse = -(1.0 + restitution) * rel_vel_normal;
+
+ if (isRigidBody())
+ {
+ MT_Vector3 temp = getInvInertiaTensor() * local2.cross(normal);
+ impulse /= invMass + normal.dot(temp.cross(local2));
+
+ /**
+ * Apply impulse at the collision point.
+ * Take rotational inertia into account.
+ */
+ applyImpulse(local2 + getNextFrame().getPosition(), impulse * normal);
+ } else {
+ /**
+ * Apply impulse through object center. (no rotation.)
+ */
+ impulse /= invMass;
+ applyCenterImpulse( impulse * normal );
+ }
+
+ MT_Vector3 external = m_combined_lin_vel + m_combined_ang_vel.cross(local2);
+ MT_Vector3 lateral = rel_vel - external - normal * (rel_vel_normal - external.dot(normal));
+#if 0
+ // test - only do friction on the physics part of the
+ // velocity.
+ vel1 -= obj1->m_combined_lin_vel;
+ vel2 -= obj2->m_combined_lin_vel;
+
+ // This should look familiar....
+ rel_vel = vel2 - vel1;
+ rel_vel_normal = normal.dot(rel_vel);
+#endif
+ /**
+ * The friction part starts here!!!!!!!!
+ *
+ * Compute the lateral component of the relative velocity
+ * lateral actually points in the opposite direction, i.e.,
+ * into the direction of the friction force.
+ */
+ if (m_shapeProps->m_do_anisotropic) {
+
+ /**
+ * For anisotropic friction we scale the lateral component,
+ * rather than compute a direction-dependent fricition
+ * factor. For this the lateral component is transformed to
+ * local coordinates.
+ */
+
+ MT_Matrix3x3 lcs(getNextFrame().getOrientation());
+
+ /**
+ * We cannot use m_xform.getBasis() for the matrix, since
+ * it might contain a non-uniform scaling.
+ * OPT: it's a bit daft to compute the matrix since the
+ * quaternion itself can be used to do the transformation.
+ */
+ MT_Vector3 loc_lateral = lateral * lcs;
+
+ /**
+ * lcs is orthogonal so lcs.inversed() == lcs.transposed(),
+ * and lcs.transposed() * lateral == lateral * lcs.
+ */
+ const MT_Vector3& friction_scaling =
+ m_shapeProps->m_friction_scaling;
+
+ // Scale the local lateral...
+ loc_lateral.scale(friction_scaling[0],
+ friction_scaling[1],
+ friction_scaling[2]);
+ // ... and transform it back to global coordinates
+ lateral = lcs * loc_lateral;
+ }
+
+ /**
+ * A tiny Coulomb friction primer:
+ * The Coulomb friction law states that the magnitude of the
+ * maximum possible friction force depends linearly on the
+ * magnitude of the normal force.
+ *
+ * \f[
+ F_max_friction = friction_factor * F_normal
+ \f]
+ *
+ * (NB: independent of the contact area!!)
+ *
+ * The friction factor depends on the material.
+ * We use impulses rather than forces but let us not be
+ * bothered by this.
+ */
+ MT_Scalar rel_vel_lateral = lateral.length();
+
+ if (rel_vel_lateral > MT_EPSILON) {
+ lateral /= rel_vel_lateral;
+
+ // Compute the maximum friction impulse
+ MT_Scalar max_friction =
+ friction_factor * MT_max(MT_Scalar(0.0), impulse);
+
+ // I guess the GEN_max is not necessary, so let's check it
+
+ MT_assert(impulse >= 0.0);
+
+ /**
+ * Here's the trick. We compute the impulse to make the
+ * lateral velocity zero. (Make the objects stick together
+ * at the contact point. If this impulse is larger than
+ * the maximum possible friction impulse, then shrink its
+ * magnitude to the maximum friction.
+ */
+
+ if (isRigidBody()) {
+
+ /**
+ * For rigid bodies we take the inertia into account,
+ * since the friction impulse is going to change the
+ * angular momentum as well.
+ */
+ MT_Vector3 temp = getInvInertiaTensor() * local2.cross(lateral);
+ MT_Scalar impulse_lateral = rel_vel_lateral /
+ (invMass + lateral.dot(temp.cross(local2)));
+
+ MT_Scalar friction = MT_min(impulse_lateral, max_friction);
+ applyImpulse(local2 + getNextFrame().getPosition(), -lateral * friction);
+ }
+ else {
+ MT_Scalar impulse_lateral = rel_vel_lateral / invMass;
+
+ MT_Scalar friction = MT_min(impulse_lateral, max_friction);
+ applyCenterImpulse( -friction * lateral);
+ }
+
+
+ }
+
+ //calcXform();
+ //notifyClient();
+
+ }
+}
+
+static void AddCallback(SM_Scene *scene, SM_Object *obj1, SM_Object *obj2)
+{
+ // If we have callbacks on either of the client objects, do a collision test
+ // and add a callback if they intersect.
+ DT_Vector3 v;
+ if ((obj1->getClientObject() && obj1->getClientObject()->hasCollisionCallback()) ||
+ (obj2->getClientObject() && obj2->getClientObject()->hasCollisionCallback()) &&
+ DT_GetIntersect(obj1->getObjectHandle(), obj2->getObjectHandle(), v))
+ scene->notifyCollision(obj1, obj2);
+}
+
+DT_Bool SM_Object::boing(
+ void *client_data,
+ void *object1,
+ void *object2,
+ const DT_CollData *coll_data
+){
+ SM_Scene *scene = (SM_Scene *)client_data;
+ SM_Object *obj1 = (SM_Object *)object1;
+ SM_Object *obj2 = (SM_Object *)object2;
+
+ // at this point it is unknown whether we are really intersecting (broad phase)
+
+ DT_Vector3 p1, p2;
+ if (!obj2->isDynamic()) {
+ std::swap(obj1, obj2);
+ }
+
+ // If one of the objects is a ghost then ignore it for the dynamics
+ if (obj1->isGhost() || obj2->isGhost()) {
+ AddCallback(scene, obj1, obj2);
+ return DT_CONTINUE;
+ }
+
+ // Objects do not collide with parent objects
+ if (obj1->getDynamicParent() == obj2 || obj2->getDynamicParent() == obj1) {
+ AddCallback(scene, obj1, obj2);
+ return DT_CONTINUE;
+ }
+
+ if (!obj2->isDynamic()) {
+ AddCallback(scene, obj1, obj2);
+ return DT_CONTINUE;
+ }
+
+ // Get collision data from SOLID
+ if (!DT_GetPenDepth(obj1->getObjectHandle(), obj2->getObjectHandle(), p1, p2))
+ return DT_CONTINUE;
+
+ MT_Point3 local1(p1), local2(p2);
+ MT_Vector3 normal(local2 - local1);
+ MT_Scalar dist = normal.length();
+
+ if (dist < MT_EPSILON)
+ return DT_CONTINUE;
+
+ // Now we are definitely intersecting.
+
+ // Set callbacks for game engine.
+ if ((obj1->getClientObject() && obj1->getClientObject()->hasCollisionCallback()) ||
+ (obj2->getClientObject() && obj2->getClientObject()->hasCollisionCallback()))
+ scene->notifyCollision(obj1, obj2);
+
+ local1 -= obj1->getNextFrame().getPosition();
+ local2 -= obj2->getNextFrame().getPosition();
+
+ // Calculate collision parameters
+ MT_Vector3 rel_vel = obj1->getVelocity(local1) - obj2->getVelocity(local2);
+
+ MT_Scalar restitution =
+ MT_min(obj1->getMaterialProps()->m_restitution,
+ obj2->getMaterialProps()->m_restitution);
+
+ MT_Scalar friction_factor =
+ MT_min(obj1->getMaterialProps()->m_friction,
+ obj2->getMaterialProps()->m_friction);
+
+ MT_Scalar invMass = obj1->getInvMass() + obj2->getInvMass();
+
+ normal /= dist;
+
+ // Calculate reactions
+ if (obj1->isDynamic())
+ obj1->dynamicCollision(local1, normal, dist, rel_vel, restitution, friction_factor, invMass);
+
+ if (obj2->isDynamic())
+ {
+ obj2->dynamicCollision(local2, -normal, dist, -rel_vel, restitution, friction_factor, invMass);
+ if (!obj1->isDynamic() || obj1->m_static)
+ obj2->m_static = obj1->m_static + 1;
+ }
+
+ return DT_CONTINUE;
+}
+
+DT_Bool SM_Object::fix(
+ void *client_data,
+ void *object1,
+ void *object2,
+ const DT_CollData *coll_data
+){
+ SM_Object *obj1 = (SM_Object *)object1;
+ SM_Object *obj2 = (SM_Object *)object2;
+
+ // If one of the objects is a ghost then ignore it for the dynamics
+ if (obj1->isGhost() || obj2->isGhost()) {
+ return DT_CONTINUE;
+ }
+
+ if (obj1->getDynamicParent() == obj2 || obj2->getDynamicParent() == obj1) {
+ return DT_CONTINUE;
+ }
+
+ if (!obj2->isDynamic()) {
+ std::swap(obj1, obj2);
+ }
+
+ if (!obj2->isDynamic()) {
+ return DT_CONTINUE;
+ }
+
+ // obj1 points to a dynamic object
+ DT_Vector3 p1, p2;
+ if (!DT_GetPenDepth(obj1->getObjectHandle(), obj2->getObjectHandle(), p1, p2))
+ return DT_CONTINUE;
+ MT_Point3 local1(p1), local2(p2);
+ // Get collision data from SOLID
+ MT_Vector3 normal(local2 - local1);
+
+ MT_Scalar dist = normal.dot(normal);
+ if (dist < MT_EPSILON || dist > obj2->m_shapeProps->m_radius*obj2->m_shapeProps->m_radius)
+ return DT_CONTINUE;
+
+
+ if ((obj1->m_static || !obj1->isDynamic()) && obj1->m_static < obj2->m_static)
+ {
+ obj2->m_static = obj1->m_static + 1;
+ } else if (obj2->m_static && obj2->m_static < obj1->m_static)
+ {
+ obj1->m_static = obj2->m_static + 1;
+ }
+
+ contacts.insert(new Contact(obj1, obj2, normal, MT_Point3(local1 + 0.5*(local2 - local1))));
+
+
+ return DT_CONTINUE;
+}
+
+void SM_Object::relax(void)
+{
+ for (Contact::Set::iterator csit = contacts.begin() ; csit != contacts.end(); ++csit)
+ {
+ (*csit)->resolve();
+ delete (*csit);
+ }
+
+ contacts.clear();
+ if (m_error.fuzzyZero())
+ return;
+ //std::cout << "SM_Object::relax: { " << m_error << " }" << std::endl;
+
+ getNextFrame().setPosition(getNextFrame().getPosition() + m_error);
+ m_error.setValue(0., 0., 0.);
+ //calcXform();
+ //notifyClient();
+}
+
+SM_Object::SM_Object() :
+ m_dynamicParent(0),
+ m_client_object(0),
+ m_physicsClientObject(0),
+ m_shape(0),
+ m_materialProps(0),
+ m_materialPropsBackup(0),
+ m_shapeProps(0),
+ m_shapePropsBackup(0),
+ m_object(0),
+ m_margin(0.0),
+ m_scaling(1.0, 1.0, 1.0),
+ m_reaction_impulse(0.0, 0.0, 0.0),
+ m_reaction_force(0.0, 0.0, 0.0),
+ m_lin_mom(0.0, 0.0, 0.0),
+ m_ang_mom(0.0, 0.0, 0.0),
+ m_force(0.0, 0.0, 0.0),
+ m_torque(0.0, 0.0, 0.0),
+ m_error(0.0, 0.0, 0.0),
+ m_combined_lin_vel (0.0, 0.0, 0.0),
+ m_combined_ang_vel (0.0, 0.0, 0.0),
+ m_fh_object(0),
+ m_kinematic(false),
+ m_prev_kinematic(false),
+ m_is_rigid_body(false)
+{
+ // warning no initialization of variables done by moto.
+}
+
+SM_Object::
+~SM_Object() {
+ if (m_fh_object)
+ delete m_fh_object;
+
+ DT_DestroyObject(m_object);
+ m_object = NULL;
+}
+
+ bool
+SM_Object::
+isDynamic(
+) const {
+ return m_shapeProps != 0;
+}
+
+/* nzc experimental. There seem to be two places where kinematics
+ * are evaluated: proceedKinematic (called from SM_Scene) and
+ * proceed() in this object. I'll just try and bunge these out for
+ * now. */
+ void
+SM_Object::
+suspend(
+){
+ if (!m_suspended) {
+ m_suspended = true;
+ suspendDynamics();
+ }
+}
+
+ void
+SM_Object::
+resume(
+) {
+ if (m_suspended) {
+ m_suspended = false;
+ restoreDynamics();
+ }
+}
+
+ void
+SM_Object::
+suspendDynamics(
+) {
+ if (m_shapeProps) {
+ m_shapePropsBackup = m_shapeProps;
+ m_shapeProps = 0;
+ }
+}
+
+ void
+SM_Object::
+restoreDynamics(
+) {
+ if (m_shapePropsBackup) {
+ m_shapeProps = m_shapePropsBackup;
+ m_shapePropsBackup = 0;
+ }
+}
+
+ bool
+SM_Object::
+isGhost(
+) const {
+ return m_materialProps == 0;
+}
+
+ void
+SM_Object::
+suspendMaterial(
+) {
+ if (m_materialProps) {
+ m_materialPropsBackup = m_materialProps;
+ m_materialProps = 0;
+ }
+}
+
+ void
+SM_Object::
+restoreMaterial(
+) {
+ if (m_materialPropsBackup) {
+ m_materialProps = m_materialPropsBackup;
+ m_materialPropsBackup = 0;
+ }
+}
+
+ SM_FhObject *
+SM_Object::
+getFhObject(
+) const {
+ return m_fh_object;
+}
+
+ void
+SM_Object::
+registerCallback(
+ SM_Callback& callback
+) {
+ m_callbackList.push_back(&callback);
+}
+
+// Set the local coordinate system according to the current state
+ void
+SM_Object::
+calcXform() {
+#ifdef SM_DEBUG_XFORM
+ printf("SM_Object::calcXform m_pos = { %-0.5f, %-0.5f, %-0.5f }\n",
+ m_pos[0], m_pos[1], m_pos[2]);
+ printf(" m_orn = { %-0.5f, %-0.5f, %-0.5f, %-0.5f }\n",
+ m_orn[0], m_orn[1], m_orn[2], m_orn[3]);
+ printf(" m_scaling = { %-0.5f, %-0.5f, %-0.5f }\n",
+ m_scaling[0], m_scaling[1], m_scaling[2]);
+#endif
+ m_xform.setOrigin(getNextFrame().getPosition());
+ m_xform.setBasis(MT_Matrix3x3(getNextFrame().getOrientation(), m_scaling));
+ m_xform.getValue(m_ogl_matrix);
+
+ /* Blender has been known to crash here.
+ This usually means SM_Object *this has been deleted more than once. */
+ DT_SetMatrixd(m_object, m_ogl_matrix);
+ if (m_fh_object) {
+ m_fh_object->setPosition(getNextFrame().getPosition());
+ m_fh_object->calcXform();
+ }
+ updateInvInertiaTensor();
+#ifdef SM_DEBUG_XFORM
+ printf("\n | %-0.5f %-0.5f %-0.5f %-0.5f |\n",
+ m_ogl_matrix[0], m_ogl_matrix[4], m_ogl_matrix[ 8], m_ogl_matrix[12]);
+ printf( " | %-0.5f %-0.5f %-0.5f %-0.5f |\n",
+ m_ogl_matrix[1], m_ogl_matrix[5], m_ogl_matrix[ 9], m_ogl_matrix[13]);
+ printf( "m_ogl_matrix = | %-0.5f %-0.5f %-0.5f %-0.5f |\n",
+ m_ogl_matrix[2], m_ogl_matrix[6], m_ogl_matrix[10], m_ogl_matrix[14]);
+ printf( " | %-0.5f %-0.5f %-0.5f %-0.5f |\n\n",
+ m_ogl_matrix[3], m_ogl_matrix[7], m_ogl_matrix[11], m_ogl_matrix[15]);
+#endif
+}
+
+ void
+SM_Object::updateInvInertiaTensor()
+{
+ m_inv_inertia_tensor = m_xform.getBasis().scaled(m_inv_inertia[0], m_inv_inertia[1], m_inv_inertia[2]) * m_xform.getBasis().transposed();
+}
+
+// Call callbacks to notify the client of a change of placement
+ void
+SM_Object::
+notifyClient() {
+ T_CallbackList::iterator i;
+ for (i = m_callbackList.begin(); i != m_callbackList.end(); ++i) {
+ (*i)->do_me();
+ }
+}
+
+
+// Save the current state information for use in the velocity computation in the next frame.
+ void
+SM_Object::
+proceedKinematic(
+ MT_Scalar timeStep
+) {
+ /* nzc: need to bunge this for the logic bubbling as well? */
+ if (!m_suspended) {
+ m_prev_kinematic = m_kinematic;
+ if (m_kinematic) {
+ m_prev_xform = m_xform;
+ m_timeStep = timeStep;
+ calcXform();
+ m_kinematic = false;
+ }
+ }
+}
+
+ void
+SM_Object::
+saveReactionForce(
+ MT_Scalar timeStep
+) {
+ if (isDynamic()) {
+ m_reaction_force = m_reaction_impulse / timeStep;
+ m_reaction_impulse.setValue(0.0, 0.0, 0.0);
+ }
+}
+
+ void
+SM_Object::
+clearForce(
+) {
+ m_force.setValue(0.0, 0.0, 0.0);
+ m_torque.setValue(0.0, 0.0, 0.0);
+}
+
+ void
+SM_Object::
+clearMomentum(
+) {
+ m_lin_mom.setValue(0.0, 0.0, 0.0);
+ m_ang_mom.setValue(0.0, 0.0, 0.0);
+}
+
+ void
+SM_Object::
+setMargin(
+ MT_Scalar margin
+) {
+ m_margin = margin;
+ DT_SetMargin(m_object, margin);
+}
+
+ MT_Scalar
+SM_Object::
+getMargin(
+) const {
+ return m_margin;
+}
+
+const
+ SM_MaterialProps *
+SM_Object::
+getMaterialProps(
+) const {
+ return m_materialProps;
+}
+
+const
+ SM_ShapeProps *
+SM_Object::
+getShapeProps(
+) const {
+ return m_shapeProps;
+}
+
+ void
+SM_Object::
+setPosition(
+ const MT_Point3& pos
+){
+ m_kinematic = true;
+ getNextFrame().setPosition(pos);
+ endFrame();
+}
+
+ void
+SM_Object::
+setOrientation(
+ const MT_Quaternion& orn
+){
+ MT_assert(!orn.fuzzyZero());
+ m_kinematic = true;
+ getNextFrame().setOrientation(orn);
+ endFrame();
+}
+
+ void
+SM_Object::
+setScaling(
+ const MT_Vector3& scaling
+){
+ m_kinematic = true;
+ m_scaling = scaling;
+}
+
+/**
+ * Functions to handle linear velocity
+ */
+
+ void
+SM_Object::
+setExternalLinearVelocity(
+ const MT_Vector3& lin_vel
+) {
+ m_combined_lin_vel=lin_vel;
+}
+
+ void
+SM_Object::
+addExternalLinearVelocity(
+ const MT_Vector3& lin_vel
+) {
+ m_combined_lin_vel+=lin_vel;
+}
+
+ void
+SM_Object::
+addLinearVelocity(
+ const MT_Vector3& lin_vel
+){
+ setLinearVelocity(getNextFrame().getLinearVelocity() + lin_vel);
+}
+
+ void
+SM_Object::
+setLinearVelocity(
+ const MT_Vector3& lin_vel
+){
+ getNextFrame().setLinearVelocity(lin_vel);
+ if (m_shapeProps) {
+ m_lin_mom = getNextFrame().getLinearVelocity() * m_shapeProps->m_mass;
+ }
+}
+
+/**
+ * Functions to handle angular velocity
+ */
+
+ void
+SM_Object::
+setExternalAngularVelocity(
+ const MT_Vector3& ang_vel
+) {
+ m_combined_ang_vel = ang_vel;
+}
+
+ void
+SM_Object::
+addExternalAngularVelocity(
+ const MT_Vector3& ang_vel
+) {
+ m_combined_ang_vel += ang_vel;
+}
+
+ void
+SM_Object::
+setAngularVelocity(
+ const MT_Vector3& ang_vel
+) {
+ getNextFrame().setAngularVelocity(ang_vel);
+ if (m_shapeProps) {
+ m_ang_mom = getNextFrame().getAngularVelocity() * m_shapeProps->m_inertia;
+ }
+}
+
+ void
+SM_Object::
+addAngularVelocity(
+ const MT_Vector3& ang_vel
+) {
+ setAngularVelocity(getNextFrame().getAngularVelocity() + ang_vel);
+}
+
+
+ void
+SM_Object::
+clearCombinedVelocities(
+) {
+ m_combined_lin_vel = MT_Vector3(0,0,0);
+ m_combined_ang_vel = MT_Vector3(0,0,0);
+}
+
+ void
+SM_Object::
+resolveCombinedVelocities(
+ const MT_Vector3 & lin_vel,
+ const MT_Vector3 & ang_vel
+) {
+
+ // Different behaviours for dynamic and non-dynamic
+ // objects. For non-dynamic we just set the velocity to
+ // zero. For dynmic the physics velocity has to be
+ // taken into account. We must make an arbitrary decision
+ // on how to resolve the 2 velocities. Choices are
+ // Add the physics velocity to the linear velocity. Objects
+ // will just keep on moving in the direction they were
+ // last set in - untill external forces affect them.
+ // Set the combinbed linear and physics velocity to zero.
+ // Set the physics velocity in the direction of the set velocity
+ // zero.
+ if (isDynamic()) {
+
+#if 1
+ getNextFrame().setLinearVelocity(getNextFrame().getLinearVelocity() + lin_vel);
+ getNextFrame().setAngularVelocity(getNextFrame().getAngularVelocity() + ang_vel);
+#else
+
+ //compute the component of the physics velocity in the
+ // direction of the set velocity and set it to zero.
+ MT_Vector3 lin_vel_norm = lin_vel.normalized();
+
+ setLinearVelocity(getNextFrame().getLinearVelocity() - (getNextFrame().getLinearVelocity().dot(lin_vel_norm) * lin_vel_norm));
+#endif
+ m_lin_mom = getNextFrame().getLinearVelocity() * m_shapeProps->m_mass;
+ m_ang_mom = getNextFrame().getAngularVelocity() * m_shapeProps->m_inertia;
+ clearCombinedVelocities();
+
+ }
+
+}
+
+
+ MT_Scalar
+SM_Object::
+getInvMass(
+) const {
+ return m_inv_mass;
+ // OPT: cache the result of this division rather than compute it each call
+}
+
+ const MT_Vector3&
+SM_Object::
+getInvInertia(
+) const {
+ return m_inv_inertia;
+ // OPT: cache the result of this division rather than compute it each call
+}
+
+ const MT_Matrix3x3&
+SM_Object::
+getInvInertiaTensor(
+) const {
+ return m_inv_inertia_tensor;
+}
+
+ void
+SM_Object::
+applyForceField(
+ const MT_Vector3& accel
+) {
+ if (m_shapeProps) {
+ m_force += m_shapeProps->m_mass * accel; // F = m * a
+ }
+}
+
+ void
+SM_Object::
+applyCenterForce(
+ const MT_Vector3& force
+) {
+ m_force += force;
+}
+
+ void
+SM_Object::
+applyTorque(
+ const MT_Vector3& torque
+) {
+ m_torque += torque;
+}
+
+ void
+SM_Object::
+applyImpulse(
+ const MT_Point3& attach, const MT_Vector3& impulse
+) {
+ applyCenterImpulse(impulse); // Change in linear momentum
+ applyAngularImpulse((attach - getNextFrame().getPosition()).cross(impulse)); // Change in angular momentump
+}
+
+ void
+SM_Object::
+applyCenterImpulse(
+ const MT_Vector3& impulse
+) {
+ if (m_shapeProps) {
+ m_lin_mom += impulse;
+ m_reaction_impulse += impulse;
+ getNextFrame().setLinearVelocity(m_lin_mom * m_inv_mass);
+
+ // The linear velocity is immedialtely updated since otherwise
+ // simultaneous collisions will get a double impulse.
+ }
+}
+
+ void
+SM_Object::
+applyAngularImpulse(
+ const MT_Vector3& impulse
+) {
+ if (m_shapeProps) {
+ m_ang_mom += impulse;
+ getNextFrame().setAngularVelocity( m_inv_inertia_tensor * m_ang_mom);
+ }
+}
+
+ MT_Point3
+SM_Object::
+getWorldCoord(
+ const MT_Point3& local
+) const {
+ return m_xform(local);
+}
+
+ MT_Vector3
+SM_Object::
+getVelocity(
+ const MT_Point3& local
+) const {
+ if (m_prev_kinematic && !isDynamic())
+ {
+ // For displaced objects the velocity is faked using the previous state.
+ // Dynamic objects get their own velocity, not the faked velocity.
+ // (Dynamic objects shouldn't be displaced in the first place!!)
+ return (m_xform(local) - m_prev_xform(local)) / m_timeStep;
+ }
+
+ // NB: m_xform.getBasis() * local == m_xform(local) - m_xform.getOrigin()
+ return actualLinVelocity() + actualAngVelocity().cross(local);
+}
+
+
+const
+ MT_Vector3&
+SM_Object::
+getReactionForce(
+) const {
+ return m_reaction_force;
+}
+
+ void
+SM_Object::
+getMatrix(
+ double *m
+) const {
+ std::copy(&m_ogl_matrix[0], &m_ogl_matrix[16], &m[0]);
+}
+
+const
+ double *
+SM_Object::
+getMatrix(
+) const {
+ return m_ogl_matrix;
+}
+
+// Still need this???
+const
+ MT_Transform&
+SM_Object::
+getScaledTransform(
+) const {
+ return m_xform;
+}
+
+ DT_ObjectHandle
+SM_Object::
+getObjectHandle(
+) const {
+ return m_object;
+}
+
+ DT_ShapeHandle
+SM_Object::
+getShapeHandle(
+) const {
+ return m_shape;
+}
+
+ SM_Object *
+SM_Object::
+getDynamicParent(
+) {
+ return m_dynamicParent;
+}
+
+ void
+SM_Object::
+setRigidBody(
+ bool is_rigid_body
+) {
+ m_is_rigid_body = is_rigid_body;
+}
+
+ bool
+SM_Object::
+isRigidBody(
+) const {
+ return m_is_rigid_body;
+}
+
+const
+ MT_Vector3
+SM_Object::
+actualLinVelocity(
+) const {
+ return m_combined_lin_vel + getNextFrame().getLinearVelocity();
+};
+
+const
+ MT_Vector3
+SM_Object::
+actualAngVelocity(
+) const {
+ return m_combined_ang_vel + getNextFrame().getAngularVelocity();
+}
+
+
+SM_MotionState&
+SM_Object::
+getCurrentFrame()
+{
+ return m_frames[1];
+}
+
+SM_MotionState&
+SM_Object::
+getPreviousFrame()
+{
+ return m_frames[0];
+}
+
+SM_MotionState &
+SM_Object::
+getNextFrame()
+{
+ return m_frames[2];
+}
+
+const SM_MotionState &
+SM_Object::
+getCurrentFrame() const
+{
+ return m_frames[1];
+}
+
+const SM_MotionState &
+SM_Object::
+getPreviousFrame() const
+{
+ return m_frames[0];
+}
+
+const SM_MotionState &
+SM_Object::
+getNextFrame() const
+{
+ return m_frames[2];
+}
+
+
+const MT_Point3&
+SM_Object::
+getPosition() const
+{
+ return m_frames[1].getPosition();
+}
+
+const MT_Quaternion&
+SM_Object::
+getOrientation() const
+{
+ return m_frames[1].getOrientation();
+}
+
+const MT_Vector3&
+SM_Object::
+getLinearVelocity() const
+{
+ return m_frames[1].getLinearVelocity();
+}
+
+const MT_Vector3&
+SM_Object::
+getAngularVelocity() const
+{
+ return m_frames[1].getAngularVelocity();
+}
+
+void
+SM_Object::
+interpolate(MT_Scalar timeStep)
+{
+ if (!actualLinVelocity().fuzzyZero() || !actualAngVelocity().fuzzyZero())
+ {
+ getCurrentFrame().setTime(timeStep);
+ getCurrentFrame().lerp(getPreviousFrame(), getNextFrame());
+ notifyClient();
+ }
+}
+
+void
+SM_Object::
+endFrame()
+{
+ getPreviousFrame() = getNextFrame();
+ getCurrentFrame() = getNextFrame();
+ m_static = 0;
+}
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp
new file mode 100644
index 00000000000..656051be4f5
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp
@@ -0,0 +1,376 @@
+/**
+ * $Id$
+ * Copyright (C) 2001 NaN Technologies B.V.
+ * The physics scene.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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(disable : 4786) // shut off 255 char limit debug template warning
+#endif
+
+#include "SM_Scene.h"
+#include "SM_Object.h"
+#include "SM_FhObject.h"
+
+#include "SM_Debug.h"
+
+#include <algorithm>
+
+SM_Scene::SM_Scene() :
+ m_scene(DT_CreateScene()),
+ m_respTable(DT_CreateRespTable()),
+ m_secondaryRespTable(DT_CreateRespTable()),
+ m_fixRespTable(DT_CreateRespTable()),
+ m_forceField(0.0, 0.0, 0.0),
+ m_frames(0)
+{
+ for (int i = 0 ; i < NUM_RESPONSE; i++)
+ {
+ m_ResponseClass[i] = DT_GenResponseClass(m_respTable);
+ m_secondaryResponseClass[i] = DT_GenResponseClass(m_secondaryRespTable);
+ m_fixResponseClass[i] = DT_GenResponseClass(m_fixRespTable);
+ }
+
+ /* Sensor */
+ DT_AddPairResponse(m_respTable, m_ResponseClass[SENSOR_RESPONSE], m_ResponseClass[SENSOR_RESPONSE], 0, DT_NO_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[SENSOR_RESPONSE], m_ResponseClass[STATIC_RESPONSE], SM_Scene::boing, DT_SIMPLE_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[SENSOR_RESPONSE], m_ResponseClass[OBJECT_RESPONSE], SM_Scene::boing, DT_SIMPLE_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[SENSOR_RESPONSE], m_ResponseClass[FH_RESPONSE], 0, DT_NO_RESPONSE, this);
+
+ /* Static */
+ DT_AddPairResponse(m_respTable, m_ResponseClass[STATIC_RESPONSE], m_ResponseClass[SENSOR_RESPONSE], SM_Scene::boing, DT_SIMPLE_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[STATIC_RESPONSE], m_ResponseClass[STATIC_RESPONSE], 0, DT_NO_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[STATIC_RESPONSE], m_ResponseClass[OBJECT_RESPONSE], SM_Object::boing, DT_BROAD_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[STATIC_RESPONSE], m_ResponseClass[FH_RESPONSE], SM_FhObject::ray_hit, DT_SIMPLE_RESPONSE, this);
+
+ /* Object */
+ DT_AddPairResponse(m_respTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[SENSOR_RESPONSE], SM_Scene::boing, DT_SIMPLE_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[STATIC_RESPONSE], SM_Object::boing, DT_BROAD_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[OBJECT_RESPONSE], SM_Object::boing, DT_BROAD_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[FH_RESPONSE], SM_FhObject::ray_hit, DT_SIMPLE_RESPONSE, this);
+
+ /* Fh Object */
+ DT_AddPairResponse(m_respTable, m_ResponseClass[FH_RESPONSE], m_ResponseClass[SENSOR_RESPONSE], 0, DT_NO_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[FH_RESPONSE], m_ResponseClass[STATIC_RESPONSE], SM_FhObject::ray_hit, DT_SIMPLE_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[FH_RESPONSE], m_ResponseClass[OBJECT_RESPONSE], SM_FhObject::ray_hit, DT_SIMPLE_RESPONSE, this);
+ DT_AddPairResponse(m_respTable, m_ResponseClass[FH_RESPONSE], m_ResponseClass[FH_RESPONSE], 0, DT_NO_RESPONSE, this);
+
+ /* Object (Fix Pass) */
+ DT_AddPairResponse(m_fixRespTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[SENSOR_RESPONSE], 0, DT_NO_RESPONSE, this);
+ DT_AddPairResponse(m_fixRespTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[STATIC_RESPONSE], SM_Object::fix, DT_BROAD_RESPONSE, this);
+ DT_AddPairResponse(m_fixRespTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[OBJECT_RESPONSE], SM_Object::fix, DT_BROAD_RESPONSE, this);
+ DT_AddPairResponse(m_fixRespTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[FH_RESPONSE], 0, DT_NO_RESPONSE, this);
+}
+
+void SM_Scene::addTouchCallback(int response_class, DT_ResponseCallback callback, void *user)
+{
+ DT_AddClassResponse(m_secondaryRespTable, m_secondaryResponseClass[response_class], callback, DT_BROAD_RESPONSE, user);
+}
+
+void SM_Scene::addSensor(SM_Object& object)
+{
+ object.calcXform();
+ m_objectList.push_back(&object);
+ DT_AddObject(m_scene, object.getObjectHandle());
+ DT_SetResponseClass(m_respTable, object.getObjectHandle(), m_ResponseClass[SENSOR_RESPONSE]);
+ DT_SetResponseClass(m_secondaryRespTable, object.getObjectHandle(), m_secondaryResponseClass[SENSOR_RESPONSE]);
+ DT_SetResponseClass(m_fixRespTable, object.getObjectHandle(), m_fixResponseClass[SENSOR_RESPONSE]);
+}
+
+void SM_Scene::add(SM_Object& object) {
+ object.calcXform();
+ m_objectList.push_back(&object);
+ DT_AddObject(m_scene, object.getObjectHandle());
+ if (object.isDynamic()) {
+ DT_SetResponseClass(m_respTable, object.getObjectHandle(), m_ResponseClass[OBJECT_RESPONSE]);
+ DT_SetResponseClass(m_secondaryRespTable, object.getObjectHandle(), m_secondaryResponseClass[OBJECT_RESPONSE]);
+ DT_SetResponseClass(m_fixRespTable, object.getObjectHandle(), m_fixResponseClass[OBJECT_RESPONSE]);
+ } else {
+ DT_SetResponseClass(m_respTable, object.getObjectHandle(), m_ResponseClass[STATIC_RESPONSE]);
+ DT_SetResponseClass(m_secondaryRespTable, object.getObjectHandle(), m_secondaryResponseClass[STATIC_RESPONSE]);
+ DT_SetResponseClass(m_fixRespTable, object.getObjectHandle(), m_fixResponseClass[STATIC_RESPONSE]);
+ }
+
+ SM_FhObject *fh_object = object.getFhObject();
+
+ if (fh_object) {
+ DT_AddObject(m_scene, fh_object->getObjectHandle());
+ DT_SetResponseClass(m_respTable, fh_object->getObjectHandle(), m_ResponseClass[FH_RESPONSE]);
+ DT_SetResponseClass(m_secondaryRespTable, fh_object->getObjectHandle(), m_secondaryResponseClass[FH_RESPONSE]);
+ DT_SetResponseClass(m_fixRespTable, fh_object->getObjectHandle(), m_fixResponseClass[FH_RESPONSE]);
+ }
+}
+
+void SM_Scene::requestCollisionCallback(SM_Object &object)
+{
+ DT_SetResponseClass(m_respTable, object.getObjectHandle(), m_ResponseClass[OBJECT_RESPONSE]);
+ DT_SetResponseClass(m_secondaryRespTable, object.getObjectHandle(), m_secondaryResponseClass[OBJECT_RESPONSE]);
+// DT_SetResponseClass(m_fixRespTable, object.getObjectHandle(), m_fixResponseClass[OBJECT_RESPONSE]);
+}
+
+void SM_Scene::remove(SM_Object& object) {
+ //std::cout << "SM_Scene::remove this =" << this << "object = " << &object << std::endl;
+ T_ObjectList::iterator i =
+ std::find(m_objectList.begin(), m_objectList.end(), &object);
+ if (!(i == m_objectList.end()))
+ {
+ std::swap(*i, m_objectList.back());
+ m_objectList.pop_back();
+ DT_RemoveObject(m_scene, object.getObjectHandle());
+
+ SM_FhObject *fh_object = object.getFhObject();
+
+ if (fh_object) {
+ DT_RemoveObject(m_scene, fh_object->getObjectHandle());
+ }
+ }
+ else {
+ // tried to remove an object that is not in the scene
+ //assert(false);
+ }
+}
+
+void SM_Scene::beginFrame()
+{
+ T_ObjectList::iterator i;
+ // Apply a forcefield (such as gravity)
+ for (i = m_objectList.begin(); i != m_objectList.end(); ++i)
+ (*i)->applyForceField(m_forceField);
+
+}
+
+void SM_Scene::endFrame()
+{
+ T_ObjectList::iterator i;
+ for (i = m_objectList.begin(); i != m_objectList.end(); ++i)
+ (*i)->clearForce();
+}
+
+bool SM_Scene::proceed(MT_Scalar curtime, MT_Scalar ticrate)
+{
+ if (!m_frames)
+ {
+ if (ticrate > 0.)
+ m_frames = (unsigned int)(curtime*ticrate) + 1.0;
+ else
+ m_frames = (unsigned int)(curtime*65536.0);
+ }
+
+ // Divide the timeStep into a number of subsamples of size roughly
+ // equal to subS (might be a little smaller).
+ MT_Scalar subStep;
+ int num_samples;
+ int frames = m_frames;
+
+ // Compute the number of steps to do this update.
+ if (ticrate > 0.0)
+ {
+ // Fixed time step
+ subStep = 1.0/ticrate;
+ num_samples = (unsigned int)(curtime*ticrate + 1.0) - m_frames;
+
+ if (num_samples > 4)
+ {
+ std::cout << "Dropping physics frames! frames:" << num_samples << " substep: " << subStep << std::endl;
+ MT_Scalar tr = ticrate;
+ do
+ {
+ frames = frames / 2;
+ tr = tr / 2.0;
+ num_samples = (unsigned int)(curtime*tr + 1.0) - frames;
+ subStep *= 2.0;
+ } while (num_samples > 8);
+ std::cout << " frames:" << num_samples << " substep: " << subStep << std::endl;
+ }
+ }
+ else
+ {
+ // Variable time step. (old update)
+ // Integrate at least 100 Hz
+ MT_Scalar timeStep = curtime - m_frames/65536.0;
+ subStep = timeStep > 0.01 ? 0.01 : timeStep;
+ num_samples = int(timeStep * 0.01);
+ if (num_samples < 1)
+ num_samples = 1;
+ }
+
+ // Do a physics timestep.
+ T_ObjectList::iterator i;
+ if (num_samples > 0)
+ {
+ // Do the integration steps per object.
+ for (int step = 0; step != num_samples; ++step)
+ {
+ MT_Scalar time;
+ if (ticrate > 0.)
+ time = MT_Scalar(frames + step + 1) * subStep;
+ else
+ time = MT_Scalar(m_frames)/65536.0 + MT_Scalar(step + 1)*subStep;
+
+ for (i = m_objectList.begin(); i != m_objectList.end(); ++i) {
+ (*i)->endFrame();
+ // Apply a forcefield (such as gravity)
+ (*i)->integrateForces(subStep);
+ // And second we update the object positions by performing
+ // an integration step for each object
+ (*i)->integrateMomentum(subStep);
+ }
+
+ // So now first we let the physics scene respond to
+ // new forces, velocities set externally.
+ // The collsion and friction impulses are computed here.
+ // Collision phase
+ DT_Test(m_scene, m_respTable);
+
+ // Contact phase
+ DT_Test(m_scene, m_fixRespTable);
+
+ // Finish this timestep by saving al state information for the next
+ // timestep and clearing the accumulated forces.
+ for (i = m_objectList.begin(); i != m_objectList.end(); ++i) {
+ (*i)->relax();
+ (*i)->proceedKinematic(subStep);
+ (*i)->saveReactionForce(subStep);
+ (*i)->getNextFrame().setTime(time);
+ //(*i)->clearForce();
+ }
+ }
+ }
+
+ if (ticrate > 0)
+ {
+ // Interpolate between time steps.
+ for (i = m_objectList.begin(); i != m_objectList.end(); ++i)
+ (*i)->interpolate(curtime);
+
+ //only update the m_frames after an actual physics timestep
+ if (num_samples)
+ {
+ m_frames = (unsigned int)(curtime*ticrate) + 1.0;
+ }
+ }
+ else
+ {
+ m_frames = (unsigned int)(curtime*65536.0);
+ }
+
+ return num_samples != 0;
+}
+
+void SM_Scene::notifyCollision(SM_Object *obj1, SM_Object *obj2)
+{
+ // For each pair of object that collided, call the corresponding callback.
+ if (m_secondaryRespTable)
+ DT_CallResponse(m_secondaryRespTable, obj1->getObjectHandle(), obj2->getObjectHandle(), 0);
+}
+
+
+SM_Object *SM_Scene::rayTest(void *ignore_client,
+ const MT_Point3& from, const MT_Point3& to,
+ MT_Point3& result, MT_Vector3& normal) const {
+#ifdef SM_DEBUG_RAYCAST
+ std::cout << "ray: { " << from << " } - { " << to << " }" << std::endl;
+#endif
+
+ DT_Vector3 n, dfrom, dto;
+ DT_Scalar param;
+ from.getValue(dfrom);
+ to.getValue(dto);
+ SM_Object *hit_object = (SM_Object *)
+ DT_RayCast(m_scene, ignore_client, dfrom, dto, 1., &param, n);
+
+ if (hit_object) {
+ //result = hit_object->getWorldCoord(from + (to - from)*param);
+ result = from + (to - from) * param;
+ normal.setValue(n);
+#ifdef SM_DEBUG_RAYCAST
+ std::cout << "ray: { " << from << " } -> { " << to << " }: { " << result
+ << " } (" << param << "), normal = { " << normal << " }" << std::endl;
+#endif
+ }
+
+ return hit_object;
+}
+
+void SM_Scene::clearObjectCombinedVelocities() {
+
+ T_ObjectList::iterator i;
+
+ for (i = m_objectList.begin(); i != m_objectList.end(); ++i) {
+
+ (*i)->clearCombinedVelocities();
+
+ }
+
+}
+
+
+void SM_Scene::setSecondaryRespTable(DT_RespTableHandle secondaryRespTable) {
+ m_secondaryRespTable = secondaryRespTable;
+}
+
+
+DT_Bool SM_Scene::boing(
+ void *client_data,
+ void *object1,
+ void *object2,
+ const DT_CollData *
+){
+ SM_Scene *scene = (SM_Scene *)client_data;
+ SM_Object *obj1 = (SM_Object *)object1;
+ SM_Object *obj2 = (SM_Object *)object2;
+
+ scene->notifyCollision(obj1, obj2); // Record this collision for client callbacks
+
+#ifdef SM_DEBUG_BOING
+ printf("SM_Scene::boing\n");
+#endif
+
+ return DT_CONTINUE;
+}
+
+SM_Scene::~SM_Scene()
+{
+ //std::cout << "SM_Scene::~ SM_Scene(): destroy " << this << std::endl;
+// if (m_objectList.begin() != m_objectList.end())
+// std::cout << "SM_Scene::~SM_Scene: There are still objects in the Sumo scene!" << std::endl;
+ for (T_ObjectList::iterator it = m_objectList.begin() ; it != m_objectList.end() ; it++)
+ delete *it;
+
+ DT_DestroyRespTable(m_respTable);
+ DT_DestroyRespTable(m_secondaryRespTable);
+ DT_DestroyRespTable(m_fixRespTable);
+ DT_DestroyScene(m_scene);
+}
diff --git a/source/gameengine/Physics/Sumo/Makefile b/source/gameengine/Physics/Sumo/Makefile
new file mode 100644
index 00000000000..bc1300c1994
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/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 *****
+#
+#
+
+SOURCEDIR = source/gameengine/Physics/Sumo
+LIBNAME = sumo
+DIR = $(OCGDIR)/gameengine/blphys/$(LIBNAME)
+DIRS = Fuzzics
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO) -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_SOLID)/include
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../Physics/common
+CPPFLAGS += -I../../Physics/Dummy
+
+include nan_subdirs.mk
diff --git a/source/gameengine/Physics/Sumo/SConscript b/source/gameengine/Physics/Sumo/SConscript
new file mode 100644
index 00000000000..be7922efd44
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/SConscript
@@ -0,0 +1,26 @@
+#!/usr/bin/python
+Import ('env')
+
+sumoenv = env.Copy()
+sources = ['SumoPHYCallbackBridge.cpp',
+ 'SumoPhysicsController.cpp',
+ 'SumoPhysicsEnvironment.cpp',
+ 'Fuzzics/src/SM_FhObject.cpp',
+ 'Fuzzics/src/SM_Object.cpp',
+ 'Fuzzics/src/SM_Scene.cpp',
+ 'Fuzzics/src/SM_MotionState.cpp'
+ ]
+
+incs =['.',
+ '../common',
+ 'Fuzzics/include',
+ '#/intern/moto/include'
+ ]
+incs += [sumoenv['BF_SOLID_INC']]
+
+cflags = []
+if env['OURPLATFORM']=='win32-vc':
+ cflags.append('/GR')
+ cflags.append('/O1')
+
+env.BlenderLib ( 'bf_sumo', sources, incs, [], libtype=['game2','player'], priority=[30, 70] , compileflags=cflags)
diff --git a/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.cpp b/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.cpp
new file mode 100644
index 00000000000..1992bbe3421
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.cpp
@@ -0,0 +1,66 @@
+#include "SumoPHYCallbackBridge.h"
+#include "PHY_IPhysicsController.h"
+#include "SM_Object.h"
+
+
+SumoPHYCallbackBridge::SumoPHYCallbackBridge(void* clientData,PHY_ResponseCallback phyCallback)
+:m_orgClientData(clientData),
+m_phyCallback(phyCallback)
+{
+
+}
+DT_Bool SumoPHYCallbackBridge::StaticSolidToPHYCallback(void *client_data,
+ void *client_object1,
+ void *client_object2,
+ const DT_CollData *coll_data)
+{
+ SumoPHYCallbackBridge* bridge = static_cast<SumoPHYCallbackBridge*>(client_data);
+ bridge->SolidToPHY(client_object1,client_object2,coll_data);
+ return false;
+}
+
+DT_Bool SumoPHYCallbackBridge::SolidToPHY(void *client_object1,
+ void *client_object2,
+ const DT_CollData *coll_data)
+{
+
+ SM_Object* smObject1 = static_cast<SM_Object*>(client_object1);
+ SM_Object* smObject2 = static_cast<SM_Object*>(client_object2);
+
+ PHY_IPhysicsController* ctrl1 = static_cast<PHY_IPhysicsController*>(smObject1->getPhysicsClientObject());
+ PHY_IPhysicsController* ctrl2 = static_cast<PHY_IPhysicsController*>(smObject2->getPhysicsClientObject());
+
+ if (!ctrl1 || !ctrl2)
+ {
+ //todo: check which objects are not linked up properly
+ return false;
+ }
+ if (coll_data)
+ {
+ PHY_CollData phyCollData;
+
+ phyCollData.m_point1[0] = coll_data->point1[0];
+ phyCollData.m_point1[1] = coll_data->point1[1];
+ phyCollData.m_point1[2] = coll_data->point1[2];
+ phyCollData.m_point1[3] = 0.f;
+
+ phyCollData.m_point2[0] = coll_data->point2[0];
+ phyCollData.m_point2[1] = coll_data->point2[1];
+ phyCollData.m_point2[2] = coll_data->point2[2];
+ phyCollData.m_point2[3] = 0.f;
+
+ phyCollData.m_normal[0] = coll_data->normal[0];
+ phyCollData.m_normal[1] = coll_data->normal[1];
+ phyCollData.m_normal[2] = coll_data->normal[2];
+ phyCollData.m_normal[3] = 0.f;
+
+
+ return m_phyCallback(m_orgClientData,
+ ctrl1,ctrl2,&phyCollData);
+ }
+
+ return m_phyCallback(m_orgClientData,
+ ctrl1,ctrl2,0);
+
+}
+
diff --git a/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.h b/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.h
new file mode 100644
index 00000000000..cc980f3961d
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.h
@@ -0,0 +1,28 @@
+#ifndef SUMO_PHY_CALLBACK_BRIDGE_H
+#define SUMO_PHY_CALLBACK_BRIDGE_H
+
+#include <SOLID/SOLID.h>
+#include "PHY_DynamicTypes.h"
+
+class SumoPHYCallbackBridge
+{
+ void* m_orgClientData;
+ PHY_ResponseCallback m_phyCallback;
+
+public:
+
+ SumoPHYCallbackBridge(void* clientData,PHY_ResponseCallback phyCallback);
+
+ static DT_Bool StaticSolidToPHYCallback(void *client_data,
+ void *client_object1,
+ void *client_object2,
+ const DT_CollData *coll_data);
+
+ DT_Bool SolidToPHY(void *client_object1,
+ void *client_object2,
+ const DT_CollData *coll_data);
+
+
+};
+
+#endif //SUMO_PHY_CALLBACK_BRIDGE_H
diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsController.cpp b/source/gameengine/Physics/Sumo/SumoPhysicsController.cpp
new file mode 100644
index 00000000000..57922e856c4
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/SumoPhysicsController.cpp
@@ -0,0 +1,493 @@
+/**
+ * @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 *****
+ */
+
+#include "SumoPhysicsController.h"
+#include "PHY_IMotionState.h"
+#include "SM_Object.h"
+#include "MT_Quaternion.h"
+
+
+SumoPhysicsController::SumoPhysicsController(
+ class SM_Scene* sumoScene,
+ class SM_Object* sumoObj,
+ class PHY_IMotionState* motionstate,
+
+ bool dyna)
+ :
+ m_sumoObj(sumoObj) ,
+ m_sumoScene(sumoScene),
+ m_bFirstTime(true),
+ m_bDyna(dyna),
+ m_MotionState(motionstate)
+{
+ if (m_sumoObj)
+ {
+
+ PHY__Vector3 pos1;
+ getPosition(pos1);
+ MT_Point3 pos(pos1);
+
+ //temp debugging check
+ //assert(pos.length() < 100000.f);
+
+ //need this to do the upcast after the solid/sumo collision callback
+ m_sumoObj->setPhysicsClientObject(this);
+ //if it is a dyna, register for a callback
+ m_sumoObj->registerCallback(*this);
+ }
+};
+
+
+
+SumoPhysicsController::~SumoPhysicsController()
+{
+ if (m_sumoObj)
+ {
+ m_sumoScene->remove(*m_sumoObj);
+
+ delete m_sumoObj;
+ m_sumoObj = NULL;
+ }
+}
+
+float SumoPhysicsController::getMass()
+{
+ if (m_sumoObj)
+ {
+ const SM_ShapeProps *shapeprops = m_sumoObj->getShapeProps();
+ if(shapeprops!=NULL) return shapeprops->m_mass;
+ }
+ return 0.f;
+}
+
+bool SumoPhysicsController::SynchronizeMotionStates(float)
+{
+ if (m_bFirstTime)
+ {
+ setSumoTransform(!m_bFirstTime);
+ m_bFirstTime = false;
+ }
+ return false;
+}
+
+
+
+
+void SumoPhysicsController::GetWorldOrientation(MT_Matrix3x3& mat)
+{
+ float orn[4];
+ m_MotionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]);
+ MT_Quaternion quat(orn);
+ mat.setRotation(quat);
+
+}
+
+void SumoPhysicsController::getPosition(PHY__Vector3& pos) const
+{
+ assert(m_sumoObj);
+
+ pos[0] = m_sumoObj->getPosition()[0];
+ pos[1] = m_sumoObj->getPosition()[0];
+ pos[2] = m_sumoObj->getPosition()[0];
+
+ //m_MotionState->getWorldPosition(pos[0],pos[1],pos[2]);
+}
+
+void SumoPhysicsController::GetWorldPosition(MT_Point3& pos)
+{
+// assert(m_sumoObj);
+
+// pos[0] = m_sumoObj->getPosition()[0];
+// pos[1] = m_sumoObj->getPosition()[0];
+// pos[2] = m_sumoObj->getPosition()[0];
+
+ float worldpos[3];
+ m_MotionState->getWorldPosition(worldpos[0],worldpos[1],worldpos[2]);
+ pos[0]=worldpos[0];
+ pos[1]=worldpos[1];
+ pos[2]=worldpos[2];
+}
+
+void SumoPhysicsController::GetWorldScaling(MT_Vector3& scale)
+{
+ float worldscale[3];
+ m_MotionState->getWorldScaling(worldscale[0],worldscale[1],worldscale[2]);
+ scale[0]=worldscale[0];
+ scale[1]=worldscale[1];
+ scale[2]=worldscale[2];
+}
+
+
+ // kinematic methods
+void SumoPhysicsController::RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local)
+{
+ if (m_sumoObj)
+ {
+ MT_Matrix3x3 mat;
+ GetWorldOrientation(mat);
+ MT_Vector3 dloc(dlocX,dlocY,dlocZ);
+
+ MT_Point3 newpos = m_sumoObj->getPosition();
+
+ newpos += (local ? mat * dloc : dloc);
+ m_sumoObj->setPosition(newpos);
+ }
+
+}
+void SumoPhysicsController::RelativeRotate(const float drot[12],bool local)
+{
+ if (m_sumoObj )
+ {
+ MT_Matrix3x3 drotmat(drot);
+ MT_Matrix3x3 currentOrn;
+ GetWorldOrientation(currentOrn);
+
+ m_sumoObj->setOrientation(m_sumoObj->getOrientation()*(local ?
+ drotmat : (currentOrn.inverse() * drotmat * currentOrn)).getRotation());
+ }
+
+}
+void SumoPhysicsController::setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal)
+{
+ m_sumoObj->setOrientation(MT_Quaternion(quatImag0,quatImag1,quatImag2,quatReal));
+}
+
+void SumoPhysicsController::getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal)
+{
+ const MT_Quaternion& q = m_sumoObj->getOrientation();
+ quatImag0 = q[0];
+ quatImag1 = q[1];
+ quatImag2 = q[2];
+ quatReal = q[3];
+}
+
+void SumoPhysicsController::setPosition(float posX,float posY,float posZ)
+{
+ m_sumoObj->setPosition(MT_Point3(posX,posY,posZ));
+}
+
+void SumoPhysicsController::setScaling(float scaleX,float scaleY,float scaleZ)
+{
+ if (!m_bDyna)
+ m_sumoObj->setScaling(MT_Vector3(scaleX,scaleY,scaleZ));
+}
+
+ // physics methods
+void SumoPhysicsController::ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local)
+{
+ if (m_sumoObj)
+ {
+ MT_Vector3 torque(torqueX,torqueY,torqueZ);
+
+ MT_Matrix3x3 orn;
+ GetWorldOrientation(orn);
+ m_sumoObj->applyTorque(local ?
+ orn * torque :
+ torque);
+ }
+}
+
+void SumoPhysicsController::ApplyForce(float forceX,float forceY,float forceZ,bool local)
+{
+ if (m_sumoObj)
+ {
+ MT_Vector3 force(forceX,forceY,forceZ);
+
+ MT_Matrix3x3 orn;
+ GetWorldOrientation(orn);
+
+ m_sumoObj->applyCenterForce(local ?
+ orn * force :
+ force);
+ }
+}
+
+void SumoPhysicsController::SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local)
+{
+ if (m_sumoObj)
+ {
+ MT_Vector3 ang_vel(ang_velX,ang_velY,ang_velZ);
+
+ MT_Matrix3x3 orn;
+ GetWorldOrientation(orn);
+
+ m_sumoObj->setExternalAngularVelocity(local ?
+ orn * ang_vel :
+ ang_vel);
+ }
+}
+
+void SumoPhysicsController::SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local)
+{
+ if (m_sumoObj )
+ {
+ MT_Matrix3x3 orn;
+ GetWorldOrientation(orn);
+
+ MT_Vector3 lin_vel(lin_velX,lin_velY,lin_velZ);
+ m_sumoObj->setExternalLinearVelocity(local ?
+ orn * lin_vel :
+ lin_vel);
+ }
+}
+
+void SumoPhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ)
+{
+ if (m_sumoObj)
+ m_sumoObj->resolveCombinedVelocities(MT_Vector3(linvelX,linvelY,linvelZ),MT_Vector3(angVelX,angVelY,angVelZ));
+}
+
+
+
+
+void SumoPhysicsController::applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ)
+{
+ if (m_sumoObj)
+ {
+ MT_Point3 attach(attachX,attachY,attachZ);
+ MT_Vector3 impulse(impulseX,impulseY,impulseZ);
+ m_sumoObj->applyImpulse(attach,impulse);
+ }
+
+}
+
+void SumoPhysicsController::SuspendDynamics()
+{
+ m_suspendDynamics=true;
+
+ if (m_sumoObj)
+ {
+ m_sumoObj->suspendDynamics();
+ m_sumoObj->setLinearVelocity(MT_Vector3(0,0,0));
+ m_sumoObj->setAngularVelocity(MT_Vector3(0,0,0));
+ m_sumoObj->calcXform();
+ }
+}
+
+void SumoPhysicsController::RestoreDynamics()
+{
+ m_suspendDynamics=false;
+
+ if (m_sumoObj)
+ {
+ m_sumoObj->restoreDynamics();
+ }
+}
+
+
+/**
+ reading out information from physics
+*/
+void SumoPhysicsController::GetLinearVelocity(float& linvX,float& linvY,float& linvZ)
+{
+ if (m_sumoObj)
+ {
+ // get velocity from the physics object (m_sumoObj)
+ const MT_Vector3& vel = m_sumoObj->getLinearVelocity();
+ linvX = vel[0];
+ linvY = vel[1];
+ linvZ = vel[2];
+ }
+ else
+ {
+ linvX = 0.f;
+ linvY = 0.f;
+ linvZ = 0.f;
+ }
+}
+
+/**
+ GetVelocity parameters are in geometric coordinates (Origin is not center of mass!).
+*/
+void SumoPhysicsController::GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ)
+{
+ if (m_sumoObj)
+ {
+ MT_Point3 pos(posX,posY,posZ);
+ // get velocity from the physics object (m_sumoObj)
+ const MT_Vector3& vel = m_sumoObj->getVelocity(pos);
+ linvX = vel[0];
+ linvY = vel[1];
+ linvZ = vel[2];
+ }
+ else
+ {
+ linvX = 0.f;
+ linvY = 0.f;
+ linvZ = 0.f;
+
+ }
+}
+
+void SumoPhysicsController::getReactionForce(float& forceX,float& forceY,float& forceZ)
+{
+ const MT_Vector3& force = m_sumoObj->getReactionForce();
+ forceX = force[0];
+ forceY = force[1];
+ forceZ = force[2];
+}
+
+void SumoPhysicsController::setRigidBody(bool rigid)
+{
+ m_sumoObj->setRigidBody(rigid);
+}
+
+void SumoPhysicsController::PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl)
+{
+ m_MotionState = motionstate;
+
+ SM_Object* dynaparent=0;
+ SumoPhysicsController* sumoparentctrl = (SumoPhysicsController* )parentctrl;
+
+ if (sumoparentctrl)
+ {
+ dynaparent = sumoparentctrl->GetSumoObject();
+ }
+
+ SM_Object* orgsumoobject = m_sumoObj;
+
+
+ m_sumoObj = new SM_Object(
+ orgsumoobject->getShapeHandle(),
+ orgsumoobject->getMaterialProps(),
+ orgsumoobject->getShapeProps(),
+ dynaparent);
+
+ m_sumoObj->setRigidBody(orgsumoobject->isRigidBody());
+
+ m_sumoObj->setMargin(orgsumoobject->getMargin());
+ m_sumoObj->setPosition(orgsumoobject->getPosition());
+ m_sumoObj->setOrientation(orgsumoobject->getOrientation());
+ //if it is a dyna, register for a callback
+ m_sumoObj->registerCallback(*this);
+
+ m_sumoScene->add(* (m_sumoObj));
+}
+
+void SumoPhysicsController::SetSimulatedTime(float)
+{
+}
+
+
+void SumoPhysicsController::WriteMotionStateToDynamics(bool)
+{
+
+}
+// this is the actual callback from sumo, and the position/orientation
+//is written to the scenegraph, using the motionstate abstraction
+
+void SumoPhysicsController::do_me()
+{
+ MT_assert(m_sumoObj);
+ const MT_Point3& pos = m_sumoObj->getPosition();
+ const MT_Quaternion& orn = m_sumoObj->getOrientation();
+
+ MT_assert(m_MotionState);
+ m_MotionState->setWorldPosition(pos[0],pos[1],pos[2]);
+ m_MotionState->setWorldOrientation(orn[0],orn[1],orn[2],orn[3]);
+}
+
+
+void SumoPhysicsController::setSumoTransform(bool nondynaonly)
+{
+ if (!nondynaonly || !m_bDyna)
+ {
+ if (m_sumoObj)
+ {
+ MT_Point3 pos;
+ GetWorldPosition(pos);
+
+ m_sumoObj->setPosition(pos);
+ if (m_bDyna)
+ {
+ m_sumoObj->setScaling(MT_Vector3(1,1,1));
+ } else
+ {
+ MT_Vector3 scale;
+ GetWorldScaling(scale);
+ m_sumoObj->setScaling(scale);
+ }
+ MT_Matrix3x3 orn;
+ GetWorldOrientation(orn);
+ m_sumoObj->setOrientation(orn.getRotation());
+ m_sumoObj->calcXform();
+ }
+ }
+}
+
+
+ // clientinfo for raycasts for example
+void* SumoPhysicsController::getNewClientInfo()
+{
+ if (m_sumoObj)
+ return m_sumoObj->getClientObject();
+ return 0;
+
+}
+void SumoPhysicsController::setNewClientInfo(void* clientinfo)
+{
+ if (m_sumoObj)
+ {
+ SM_ClientObject* clOb = static_cast<SM_ClientObject*> (clientinfo);
+ m_sumoObj->setClientObject(clOb);
+ }
+
+}
+
+void SumoPhysicsController::calcXform()
+{
+ if (m_sumoObj)
+ m_sumoObj->calcXform();
+}
+
+void SumoPhysicsController::SetMargin(float margin)
+{
+ if (m_sumoObj)
+ m_sumoObj->setMargin(margin);
+}
+
+float SumoPhysicsController::GetMargin() const
+{
+ if (m_sumoObj)
+ m_sumoObj->getMargin();
+ return 0.f;
+}
+
+float SumoPhysicsController::GetRadius() const
+{
+ if (m_sumoObj && m_sumoObj->getShapeProps())
+ {
+ return m_sumoObj->getShapeProps()->m_radius;
+ }
+ return 0.f;
+
+}
diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsController.h b/source/gameengine/Physics/Sumo/SumoPhysicsController.h
new file mode 100644
index 00000000000..349c8cc24a6
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/SumoPhysicsController.h
@@ -0,0 +1,188 @@
+/**
+ * @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 __SUMO_PHYSICSCONTROLLER_H
+#define __SUMO_PHYSICSCONTROLLER_H
+
+#include "PHY_IPhysicsController.h"
+#include "SM_Scene.h"
+#include "SM_Callback.h"
+
+/**
+ * Sumo Physics Controller, a special kind of a PhysicsController.
+ * A Physics Controller is a special kind of Scene Graph Transformation Controller.
+ * Each time the scene graph get's updated, the controller get's a chance
+ * in the 'Update' method to reflect changes.
+ *
+ * Sumo uses the SOLID library for collision detection.
+ */
+class SumoPhysicsController : public PHY_IPhysicsController , public SM_Callback
+
+
+{
+
+
+public:
+ SumoPhysicsController(
+ class SM_Scene* sumoScene,
+ class SM_Object* sumoObj,
+ class PHY_IMotionState* motionstate,
+ bool dyna);
+
+ virtual ~SumoPhysicsController();
+
+ /**
+ * @name Kinematic Methods.
+ */
+ /*@{*/
+ virtual void RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local);
+ /**
+ * @param drot a 3x4 matrix. This will treated as a 3x3 rotation matrix.
+ * @warning RelativeRotate expects a 3x4 matrix. The fourth column is padding.
+ */
+ virtual void RelativeRotate(const float drot[12],bool local);
+ virtual void getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal);
+ virtual void setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal);
+ virtual void setPosition(float posX,float posY,float posZ);
+ virtual void getPosition(PHY__Vector3& pos) const;
+
+ virtual void setScaling(float scaleX,float scaleY,float scaleZ);
+ /*@}*/
+
+ /**
+ * @name Physics Methods
+ */
+ /*@{*/
+ virtual void ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local);
+ virtual void ApplyForce(float forceX,float forceY,float forceZ,bool local);
+ virtual void SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local);
+ virtual void SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local);
+ virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ);
+ virtual void applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ);
+ virtual void SetActive(bool active){};
+ virtual void SuspendDynamics();
+ virtual void RestoreDynamics();
+ /*@}*/
+
+
+ /**
+ * reading out information from physics
+ */
+ virtual void GetLinearVelocity(float& linvX,float& linvY,float& linvZ);
+ /**
+ * GetVelocity parameters are in geometric coordinates (Origin is not center of mass!).
+ */
+ virtual void GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ);
+ virtual float getMass();
+ virtual void getReactionForce(float& forceX,float& forceY,float& forceZ);
+ virtual void setRigidBody(bool rigid);
+
+
+ virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl);
+
+ // TODO: remove next line !
+ virtual void SetSimulatedTime(float time);
+
+ virtual void WriteDynamicsToMotionState() {};
+ virtual void WriteMotionStateToDynamics(bool nondynaonly);
+
+ /**
+ * call from Scene Graph Node to 'update'.
+ */
+ virtual bool SynchronizeMotionStates(float time);
+
+ virtual void calcXform();
+ virtual void SetMargin(float margin) ;
+ virtual float GetMargin() const;
+ virtual float GetRadius() const ;
+
+
+ // clientinfo for raycasts for example
+ virtual void* getNewClientInfo();
+ virtual void setNewClientInfo(void* clientinfo);
+
+ float getFriction() { return m_friction;}
+ float getRestitution() { return m_restitution;}
+
+ /**
+ * Sumo callback
+ */
+ virtual void do_me();
+
+ class SM_Object* GetSumoObject ()
+ {
+ return m_sumoObj;
+ };
+
+ void GetWorldOrientation(class MT_Matrix3x3& mat);
+ void GetWorldPosition(MT_Point3& pos);
+ void GetWorldScaling(MT_Vector3& scale);
+
+
+// void SetSumoObject(class SM_Object* sumoObj) {
+// m_sumoObj = sumoObj;
+// }
+// void SetSumoScene(class SM_Scene* sumoScene) {
+// m_sumoScene = sumoScene;
+// }
+
+ void setSumoTransform(bool nondynaonly);
+
+
+private:
+ class SM_Object* m_sumoObj;
+ class SM_Scene* m_sumoScene; // needed for replication
+ bool m_bFirstTime;
+ bool m_bDyna;
+
+ float m_friction;
+ float m_restitution;
+
+
+ bool m_suspendDynamics;
+
+ bool m_firstTime;
+ bool m_bFullRigidBody;
+ bool m_bPhantom; // special flag for objects that are not affected by physics 'resolver'
+
+ // data to calculate fake velocities for kinematic objects (non-dynas)
+ bool m_bKinematic;
+ bool m_bPrevKinematic;
+
+ float m_lastTime;
+
+ class PHY_IMotionState* m_MotionState;
+
+
+};
+
+#endif //__SUMO_PHYSICSCONTROLLER_H
+
diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp
new file mode 100644
index 00000000000..6cdf1d41dc1
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp
@@ -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 "SumoPhysicsEnvironment.h"
+#include "PHY_IMotionState.h"
+#include "SumoPhysicsController.h"
+#include "SM_Scene.h"
+#include "SumoPHYCallbackBridge.h"
+#include <SOLID/SOLID.h>
+
+SumoPhysicsEnvironment::SumoPhysicsEnvironment()
+{
+ m_fixedTimeStep = 1.f/60.f;
+ m_useFixedTimeStep = true;
+ m_currentTime = 0.f;
+
+ m_sumoScene = new SM_Scene();
+}
+
+
+
+SumoPhysicsEnvironment::~SumoPhysicsEnvironment()
+{
+ delete m_sumoScene;
+}
+
+
+
+void SumoPhysicsEnvironment::beginFrame()
+{
+ m_sumoScene->beginFrame();
+}
+
+void SumoPhysicsEnvironment::endFrame()
+{
+ m_sumoScene->endFrame();
+}
+
+void SumoPhysicsEnvironment::setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep)
+{
+ m_useFixedTimeStep = useFixedTimeStep;
+ if (m_useFixedTimeStep)
+ {
+ m_fixedTimeStep = fixedTimeStep;
+ } else
+ {
+ m_fixedTimeStep = 0.f;
+ }
+ //reset current time ?
+ m_currentTime = 0.f;
+}
+float SumoPhysicsEnvironment::getFixedTimeStep()
+{
+ return m_fixedTimeStep;
+}
+
+
+bool SumoPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep)
+{
+
+ bool result = false;
+ if (m_useFixedTimeStep)
+ {
+ m_currentTime += timeStep;
+ float ticrate = 1.f/m_fixedTimeStep;
+
+ result = m_sumoScene->proceed(curTime, ticrate);
+ } else
+ {
+ m_currentTime += timeStep;
+ result = m_sumoScene->proceed(m_currentTime, timeStep);
+ }
+ return result;
+}
+
+void SumoPhysicsEnvironment::setGravity(float x,float y,float z)
+{
+ m_sumoScene->setForceField(MT_Vector3(x,y,z));
+}
+
+int SumoPhysicsEnvironment::createConstraint(
+ class PHY_IPhysicsController* ctrl,
+ class PHY_IPhysicsController* ctrl2,
+ PHY_ConstraintType type,
+ float pivotX,float pivotY,float pivotZ,
+ float axisX,float axisY,float axisZ,
+ float axis1X,float axis1Y,float axis1Z,
+ float axis2X,float axis2Y,float axis2Z
+
+ )
+{
+ int constraintid = 0;
+ return constraintid;
+}
+
+void SumoPhysicsEnvironment::removeConstraint(int constraintid)
+{
+ if (constraintid)
+ {
+ }
+}
+
+PHY_IPhysicsController* SumoPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClientCtrl,
+ float fromX,float fromY,float fromZ,
+ float toX,float toY,float toZ,
+ float& hitX,float& hitY,float& hitZ,
+ float& normalX,float& normalY,float& normalZ)
+{
+ SumoPhysicsController* ignoreCtr = static_cast<SumoPhysicsController*> (ignoreClientCtrl);
+
+ //collision detection / raytesting
+ MT_Point3 hit, normal;
+ PHY_IPhysicsController *ret = 0;
+
+ SM_Object* sm_ignore = 0;
+ if (ignoreCtr)
+ sm_ignore = ignoreCtr->GetSumoObject();
+
+
+ SM_Object* smOb = m_sumoScene->rayTest(sm_ignore,MT_Point3(fromX, fromY, fromZ),MT_Point3(toX, toY, toZ), hit, normal);
+ if (smOb)
+ {
+ ret = (PHY_IPhysicsController *) smOb->getPhysicsClientObject();
+ }
+ hitX = hit[0];
+ hitY = hit[1];
+ hitZ = hit[2];
+
+ normalX = normal[0];
+ normalY = normal[1];
+ normalZ = normal[2];
+
+ return ret;
+}
+//gamelogic callbacks
+void SumoPhysicsEnvironment::addSensor(PHY_IPhysicsController* ctrl)
+{
+ SumoPhysicsController* smctrl = dynamic_cast<SumoPhysicsController*>(ctrl);
+ SM_Object* smObject = smctrl->GetSumoObject();
+ assert(smObject);
+ if (smObject)
+ {
+ m_sumoScene->addSensor(*smObject);
+ }
+}
+void SumoPhysicsEnvironment::removeSensor(PHY_IPhysicsController* ctrl)
+{
+ SumoPhysicsController* smctrl = dynamic_cast<SumoPhysicsController*>(ctrl);
+ SM_Object* smObject = smctrl->GetSumoObject();
+ assert(smObject);
+ if (smObject)
+ {
+ m_sumoScene->remove(*smObject);
+ }
+}
+
+
+void SumoPhysicsEnvironment::addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user)
+{
+
+ int sumoRespClass = 0;
+
+ //map PHY_ convention into SM_ convention
+ switch (response_class)
+ {
+ case PHY_FH_RESPONSE:
+ sumoRespClass = FH_RESPONSE;
+ break;
+ case PHY_SENSOR_RESPONSE:
+ sumoRespClass = SENSOR_RESPONSE;
+ break;
+ case PHY_CAMERA_RESPONSE:
+ sumoRespClass =CAMERA_RESPONSE;
+ break;
+ case PHY_OBJECT_RESPONSE:
+ sumoRespClass = OBJECT_RESPONSE;
+ break;
+ case PHY_STATIC_RESPONSE:
+ sumoRespClass = PHY_STATIC_RESPONSE;
+ break;
+ default:
+ assert(0);
+ return;
+ }
+
+ SumoPHYCallbackBridge* bridge = new SumoPHYCallbackBridge(user,callback);
+
+ m_sumoScene->addTouchCallback(sumoRespClass,SumoPHYCallbackBridge::StaticSolidToPHYCallback,bridge);
+}
+void SumoPhysicsEnvironment::requestCollisionCallback(PHY_IPhysicsController* ctrl)
+{
+ SumoPhysicsController* smctrl = dynamic_cast<SumoPhysicsController*>(ctrl);
+ MT_assert(smctrl);
+ SM_Object* smObject = smctrl->GetSumoObject();
+ MT_assert(smObject);
+ if (smObject)
+ {
+ //assert(smObject->getPhysicsClientObject() == ctrl);
+ smObject->setPhysicsClientObject(ctrl);
+
+ m_sumoScene->requestCollisionCallback(*smObject);
+ }
+}
+PHY_IPhysicsController* SumoPhysicsEnvironment::CreateSphereController(float radius,const PHY__Vector3& position)
+{
+ DT_ShapeHandle shape = DT_NewSphere(0.0);
+ SM_Object* ob = new SM_Object(shape,0,0,0);
+ ob->setPosition(MT_Point3(position));
+ //testing
+ MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(90));
+ ob->setOrientation(rotquatje);
+
+ PHY_IPhysicsController* ctrl = new SumoPhysicsController(m_sumoScene,ob,0,false);
+ ctrl->SetMargin(radius);
+ return ctrl;
+}
+PHY_IPhysicsController* SumoPhysicsEnvironment::CreateConeController(float coneradius,float coneheight)
+{
+ DT_ShapeHandle shape = DT_NewCone(coneradius,coneheight);
+ SM_Object* ob = new SM_Object(shape,0,0,0);
+ ob->setPosition(MT_Point3(0.f,0.f,0.f));
+ MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(90));
+ ob->setOrientation(rotquatje);
+
+ PHY_IPhysicsController* ctrl = new SumoPhysicsController(m_sumoScene,ob,0,false);
+
+ return ctrl;
+}
+
diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h
new file mode 100644
index 00000000000..4d17d0c21fd
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.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 _SUMOPhysicsEnvironment
+#define _SUMOPhysicsEnvironment
+
+#include "MT_Scalar.h"
+
+#include "PHY_IPhysicsEnvironment.h"
+class SumoPHYCallbackBridge;
+#include <vector>
+/**
+* Physics Environment takes care of stepping the simulation and is a container for physics entities (rigidbodies,constraints, materials etc.)
+* A derived class may be able to 'construct' entities by loading and/or converting
+*/
+class SumoPhysicsEnvironment : public PHY_IPhysicsEnvironment
+{
+
+ class SM_Scene* m_sumoScene;
+ float m_currentTime;
+ float m_fixedTimeStep;
+ bool m_useFixedTimeStep;
+
+ std::vector<SumoPHYCallbackBridge*> m_callbacks;
+
+public:
+ SumoPhysicsEnvironment();
+ virtual ~SumoPhysicsEnvironment();
+ virtual void beginFrame();
+ virtual void endFrame();
+// Perform an integration step of duration 'timeStep'.
+ virtual bool proceedDeltaTime(double curTime,float timeStep);
+ virtual void setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep);
+ virtual float getFixedTimeStep();
+
+ virtual void setGravity(float x,float y,float z);
+ virtual int createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type,
+ float pivotX,float pivotY,float pivotZ,
+ float axisX,float axisY,float axisZ,
+ float axis1X=0,float axis1Y=0,float axis1Z=0,
+ float axis2X=0,float axis2Y=0,float axis2Z=0
+
+ );
+
+ virtual void removeConstraint(int constraintid);
+
+ //complex constraint for vehicles
+ virtual PHY_IVehicle* getVehicleConstraint(int constraintId)
+ {
+ return 0;
+ }
+
+ virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ,
+ float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ);
+
+
+ //gamelogic callbacks
+ virtual void addSensor(PHY_IPhysicsController* ctrl);
+ virtual void removeSensor(PHY_IPhysicsController* ctrl);
+ virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user);
+ virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl);
+ virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position);
+ virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight);
+
+ virtual void setConstraintParam(int constraintId,int param,float value,float value1)
+ {
+ }
+ SM_Scene* GetSumoScene()
+ {
+ return m_sumoScene;
+ }
+
+protected:
+ // 60Hz (Default)
+ static MT_Scalar PhysicsTicRate;
+
+};
+
+#endif //_SUMOPhysicsEnvironment
+
diff --git a/source/gameengine/Physics/Sumo/convert.txt b/source/gameengine/Physics/Sumo/convert.txt
new file mode 100644
index 00000000000..81f8f602cde
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/convert.txt
@@ -0,0 +1,35 @@
+static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj)
+{
+ DT_ShapeHandle shape = DT_NewComplexShape();
+ int numpolys = meshobj->NumPolygons();
+ int numvalidpolys = 0;
+
+ for (int p=0; p<numpolys; p++)
+ {
+ RAS_Polygon* poly = meshobj->GetPolygon(p);
+
+ // only add polygons that have the collisionflag set
+ if (poly->IsCollider())
+ {
+ DT_Begin();
+ for (int v=0; v<poly->VertexCount(); v++) {
+ MT_Point3 pt = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
+ poly->GetVertexIndexBase().m_indexarray[v],
+ poly->GetMaterial()->GetPolyMaterial())->xyz();
+ DT_Vertex(pt[0],pt[1],pt[2]);
+ }
+ DT_End();
+
+ numvalidpolys++;
+ }
+ }
+
+ DT_EndComplexShape();
+
+ if (numvalidpolys==0) {
+ delete shape;
+ return NULL;
+ } else {
+ return shape;
+ }
+}
diff --git a/source/gameengine/Physics/Sumo/include/interpolator.h b/source/gameengine/Physics/Sumo/include/interpolator.h
new file mode 100644
index 00000000000..055c242edc7
--- /dev/null
+++ b/source/gameengine/Physics/Sumo/include/interpolator.h
@@ -0,0 +1,27 @@
+#ifndef INTERPOLATOR_H
+#define INTERPOLATOR_H
+
+#include "solid_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+DT_DECLARE_HANDLE(IP_IpoHandle);
+
+typedef struct IP_ControlPoint {
+ DT_Scalar m_key;
+ DT_Scalar m_keyValue;
+} IP_ControlPoint;
+
+IP_IpoHandle IP_CreateLinear(const IP_ControlPoint *cpoints, int num_cpoints);
+
+void IP_DeleteInterpolator(IP_IpoHandle ipo);
+
+DT_Scalar IP_GetValue(IP_IpoHandle ipo, DT_Scalar key);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/gameengine/Physics/common/CMakeLists.txt b/source/gameengine/Physics/common/CMakeLists.txt
new file mode 100644
index 00000000000..57e835bb4c2
--- /dev/null
+++ b/source/gameengine/Physics/common/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 *****
+
+SET(SRC PHY_IMotionState.cpp PHY_IPhysicsController.cpp PHY_IPhysicsEnvironment.cpp PHY_IVehicle.cpp)
+
+SET(INC
+ .
+ ../Dummy
+ ../../../intern/moto/include
+)
+
+BLENDERLIB(bf_common "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_common', Split(sources), Split(incs), [], libtype=['game', 'game2','player'], priority=[20, 35, 95] )
diff --git a/source/gameengine/Physics/common/Makefile b/source/gameengine/Physics/common/Makefile
new file mode 100644
index 00000000000..e0f72571c96
--- /dev/null
+++ b/source/gameengine/Physics/common/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 = common
+DIR = $(OCGDIR)/gameengine/blphys/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO)/include -I$(NAN_MOTO)/include
+CPPFLAGS += -I../../blender
+# these two needed because of blenkernel
+CPPFLAGS += -I../../blender/makesdna
+CPPFLAGS += -I../../blender/include
+CPPFLAGS += -I../../blender/blenlib
+CPPFLAGS += -I../../blender/blenkernel
+CPPFLAGS += -I../../blender/render/extern/include
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../Expressions -I../Rasterizer -I../GameLogic
+CPPFLAGS += -I../Ketsji -I../BlenderRoutines -I../SceneGraph
+CPPFLAGS += -I../../kernel/gen_system
+CPPFLAGS += -I../Rasterizer/RAS_OpenGLRasterizer
+CPPFLAGS += -I../Network -I../Ketsji/KXNetwork
+CPPFLAGS += -I../Physics
+CPPFLAGS += -I../Physics/Dummy
diff --git a/source/gameengine/Physics/common/PHY_DynamicTypes.h b/source/gameengine/Physics/common/PHY_DynamicTypes.h
new file mode 100644
index 00000000000..68b60192fbc
--- /dev/null
+++ b/source/gameengine/Physics/common/PHY_DynamicTypes.h
@@ -0,0 +1,93 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+#ifndef __PHY_DYNAMIC_TYPES
+#define __PHY_DYNAMIC_TYPES
+
+
+
+class PHY_ResponseTable;
+
+class PHY_Shape;
+
+struct PHY__Vector3
+{
+ float m_vec[4];
+ operator const float* () const
+ {
+ return &m_vec[0];
+ }
+ operator float* ()
+ {
+ return &m_vec[0];
+ }
+};
+//typedef float PHY__Vector3[4];
+
+typedef enum
+{
+ PHY_FH_RESPONSE,
+ PHY_SENSOR_RESPONSE, /* Touch Sensors */
+ PHY_CAMERA_RESPONSE, /* Visibility Culling */
+ PHY_OBJECT_RESPONSE, /* Object Dynamic Geometry Response */
+ PHY_STATIC_RESPONSE, /* Static Geometry Response */
+
+ PHY_NUM_RESPONSE
+};
+
+ typedef struct PHY_CollData {
+ PHY__Vector3 m_point1; /* Point in object1 in world coordinates */
+ PHY__Vector3 m_point2; /* Point in object2 in world coordinates */
+ PHY__Vector3 m_normal; /* point2 - point1 */
+ } PHY_CollData;
+
+
+ typedef bool (*PHY_ResponseCallback)(void *client_data,
+ void *client_object1,
+ void *client_object2,
+ const PHY_CollData *coll_data);
+
+
+
+/// PHY_PhysicsType enumerates all possible Physics Entities.
+/// It is mainly used to create/add Physics Objects
+
+typedef enum PHY_PhysicsType {
+ PHY_CONVEX_RIGIDBODY=16386,
+ PHY_CONCAVE_RIGIDBODY=16399,
+ PHY_CONVEX_FIXEDBODY=16388,//'collision object'
+ PHY_CONCAVE_FIXEDBODY=16401,
+ PHY_CONVEX_KINEMATICBODY=16387,//
+ PHY_CONCAVE_KINEMATICBODY=16400,
+ PHY_CONVEX_PHANTOMBODY=16398,
+ PHY_CONCAVE_PHANTOMBODY=16402
+} PHY_PhysicsType;
+
+/// PHY_ConstraintType enumerates all supported Constraint Types
+typedef enum PHY_ConstraintType {
+ PHY_POINT2POINT_CONSTRAINT=1,
+ PHY_LINEHINGE_CONSTRAINT=2,
+ PHY_ANGULAR_CONSTRAINT = 3,//hinge without ball socket
+ PHY_CONE_TWIST_CONSTRAINT = 4,
+ PHY_VEHICLE_CONSTRAINT=11,//complex 'constraint' that turns a rigidbody into a vehicle
+ PHY_GENERIC_6DOF_CONSTRAINT=12,//can leave any of the 6 degree of freedom 'free' or 'locked'
+
+} PHY_ConstraintType;
+
+typedef float PHY_Vector3[3];
+
+#endif //__PHY_DYNAMIC_TYPES
+
diff --git a/source/gameengine/Physics/common/PHY_IMotionState.cpp b/source/gameengine/Physics/common/PHY_IMotionState.cpp
new file mode 100644
index 00000000000..355f1910dc1
--- /dev/null
+++ b/source/gameengine/Physics/common/PHY_IMotionState.cpp
@@ -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 *****
+ */
+#include "PHY_IMotionState.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+PHY_IMotionState::~PHY_IMotionState()
+{
+
+}
diff --git a/source/gameengine/Physics/common/PHY_IMotionState.h b/source/gameengine/Physics/common/PHY_IMotionState.h
new file mode 100644
index 00000000000..3dc319e040e
--- /dev/null
+++ b/source/gameengine/Physics/common/PHY_IMotionState.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef PHY__MOTIONSTATE_H
+#define PHY__MOTIONSTATE_H
+
+/**
+ PHY_IMotionState is the Interface to explicitly synchronize the world transformation.
+ Default implementations for mayor graphics libraries like OpenGL and DirectX can be provided.
+*/
+class PHY_IMotionState
+
+{
+ public:
+
+ virtual ~PHY_IMotionState();
+
+ virtual void getWorldPosition(float& posX,float& posY,float& posZ)=0;
+ virtual void getWorldScaling(float& scaleX,float& scaleY,float& scaleZ)=0;
+ virtual void getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal)=0;
+
+ virtual void setWorldPosition(float posX,float posY,float posZ)=0;
+ virtual void setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal)=0;
+
+ virtual void calculateWorldTransformations()=0;
+};
+
+#endif //PHY__MOTIONSTATE_H
+
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.cpp b/source/gameengine/Physics/common/PHY_IPhysicsController.cpp
new file mode 100644
index 00000000000..34849a55817
--- /dev/null
+++ b/source/gameengine/Physics/common/PHY_IPhysicsController.cpp
@@ -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 *****
+ */
+#include "PHY_IPhysicsController.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+PHY_IPhysicsController::~PHY_IPhysicsController()
+{
+
+}
+
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h
new file mode 100644
index 00000000000..931dc0e988c
--- /dev/null
+++ b/source/gameengine/Physics/common/PHY_IPhysicsController.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 PHY_IPHYSICSCONTROLLER_H
+#define PHY_IPHYSICSCONTROLLER_H
+
+#include "PHY_DynamicTypes.h"
+
+
+
+/**
+ PHY_IPhysicsController is the abstract simplified Interface to a physical object.
+ It contains the IMotionState and IDeformableMesh Interfaces.
+*/
+class PHY_IPhysicsController
+{
+
+ public:
+
+ virtual ~PHY_IPhysicsController();
+ /**
+ SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
+ */
+ virtual bool SynchronizeMotionStates(float time)=0;
+ /**
+ WriteMotionStateToDynamics ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
+ */
+
+ virtual void WriteMotionStateToDynamics(bool nondynaonly)=0;
+ virtual void WriteDynamicsToMotionState()=0;
+ // controller replication
+ virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl)=0;
+
+ // kinematic methods
+ virtual void RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local)=0;
+ virtual void RelativeRotate(const float drot[12],bool local)=0;
+ virtual void getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal)=0;
+ virtual void setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal)=0;
+ virtual void setPosition(float posX,float posY,float posZ)=0;
+ virtual void getPosition(PHY__Vector3& pos) const=0;
+ virtual void setScaling(float scaleX,float scaleY,float scaleZ)=0;
+
+ // physics methods
+ virtual void ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local)=0;
+ virtual void ApplyForce(float forceX,float forceY,float forceZ,bool local)=0;
+ virtual void SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local)=0;
+ virtual void SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local)=0;
+ virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) = 0;
+
+ virtual void applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ)=0;
+ virtual void SetActive(bool active)=0;
+
+ // reading out information from physics
+ virtual void GetLinearVelocity(float& linvX,float& linvY,float& linvZ)=0;
+ virtual void GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ)=0;
+ virtual void getReactionForce(float& forceX,float& forceY,float& forceZ)=0;
+
+ // dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted
+ virtual void setRigidBody(bool rigid)=0;
+
+ // clientinfo for raycasts for example
+ virtual void* getNewClientInfo()=0;
+ virtual void setNewClientInfo(void* clientinfo)=0;
+ virtual PHY_IPhysicsController* GetReplica() {return 0;}
+
+ virtual void calcXform() =0;
+ virtual void SetMargin(float margin) =0;
+ virtual float GetMargin() const=0;
+ virtual float GetRadius() const { return 0.f;}
+ PHY__Vector3 GetWorldPosition(PHY__Vector3& localpos);
+
+};
+
+#endif //PHY_IPHYSICSCONTROLLER_H
+
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.cpp b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.cpp
new file mode 100644
index 00000000000..2ba982b4442
--- /dev/null
+++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.cpp
@@ -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 *****
+ */
+
+#include "PHY_IPhysicsEnvironment.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/**
+* Physics Environment takes care of stepping the simulation and is a container for physics entities (rigidbodies,constraints, materials etc.)
+* A derived class may be able to 'construct' entities by loading and/or converting
+*/
+
+
+
+PHY_IPhysicsEnvironment::~PHY_IPhysicsEnvironment()
+{
+
+}
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
new file mode 100644
index 00000000000..5e4fd681914
--- /dev/null
+++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
@@ -0,0 +1,117 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 _IPHYSICSENVIRONMENT
+#define _IPHYSICSENVIRONMENT
+
+#include <vector>
+#include "PHY_DynamicTypes.h"
+class PHY_IVehicle;
+
+/**
+* Physics Environment takes care of stepping the simulation and is a container for physics entities (rigidbodies,constraints, materials etc.)
+* A derived class may be able to 'construct' entities by loading and/or converting
+*/
+class PHY_IPhysicsEnvironment
+{
+ public:
+ virtual ~PHY_IPhysicsEnvironment();
+ virtual void beginFrame() = 0;
+ virtual void endFrame() = 0;
+ /// Perform an integration step of duration 'timeStep'.
+ virtual bool proceedDeltaTime(double curTime,float timeStep)=0;
+ virtual void setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep)=0;
+ //returns 0.f if no fixed timestep is used
+ virtual float getFixedTimeStep()=0;
+
+ ///setDebugMode is used to support several ways of debug lines, contact point visualization
+ virtual void setDebugMode(int debugMode) {}
+ ///setNumIterations set the number of iterations for iterative solvers
+ virtual void setNumIterations(int numIter) {}
+ ///setNumTimeSubSteps set the number of divisions of the timestep. Tradeoff quality versus performance.
+ virtual void setNumTimeSubSteps(int numTimeSubSteps){}
+ ///setDeactivationTime sets the minimum time that an objects has to stay within the velocity tresholds until it gets fully deactivated
+ virtual void setDeactivationTime(float dTime) {}
+ ///setDeactivationLinearTreshold sets the linear velocity treshold, see setDeactivationTime
+ virtual void setDeactivationLinearTreshold(float linTresh) {}
+ ///setDeactivationAngularTreshold sets the angular velocity treshold, see setDeactivationTime
+ virtual void setDeactivationAngularTreshold(float angTresh) {}
+ ///setContactBreakingTreshold sets tresholds to do with contact point management
+ virtual void setContactBreakingTreshold(float contactBreakingTreshold) {}
+ ///continuous collision detection mode, very experimental for Bullet
+ virtual void setCcdMode(int ccdMode) {}
+ ///successive overrelaxation constant, in case PSOR is used, values in between 1 and 2 guarantee converging behaviour
+ virtual void setSolverSorConstant(float sor) {}
+ ///setSolverType, internal setting, chooses solvertype, PSOR, Dantzig, impulse based, penalty based
+ virtual void setSolverType(int solverType) {}
+ ///setTau sets the spring constant of a penalty based solver
+ virtual void setSolverTau(float tau) {}
+ ///setDamping sets the damper constant of a penalty based solver
+ virtual void setSolverDamping(float damping) {}
+ ///linear air damping for rigidbodies
+ virtual void setLinearAirDamping(float damping) {}
+ /// penetrationdepth setting
+ virtual void setUseEpa(bool epa) {}
+
+ virtual void setGravity(float x,float y,float z)=0;
+
+ virtual int createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type,
+ float pivotX,float pivotY,float pivotZ,
+ float axis0X,float axis0Y,float axis0Z,
+ float axis1X=0,float axis1Y=0,float axis1Z=0,
+ float axis2X=0,float axis2Y=0,float axis2Z=0
+ )=0;
+ virtual void removeConstraint(int constraintid)=0;
+ virtual float getAppliedImpulse(int constraintid){ return 0.f;}
+
+
+ //complex constraint for vehicles
+ virtual PHY_IVehicle* getVehicleConstraint(int constraintId) =0;
+
+ virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ,
+ float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ)=0;
+
+
+ //Methods for gamelogic collision/physics callbacks
+ //todo:
+ virtual void addSensor(PHY_IPhysicsController* ctrl)=0;
+ virtual void removeSensor(PHY_IPhysicsController* ctrl)=0;
+ virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user)=0;
+ virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl)=0;
+ virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position) =0;
+ virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight)=0;
+
+ virtual void setConstraintParam(int constraintId,int param,float value,float value1) = 0;
+};
+
+#endif //_IPHYSICSENVIRONMENT
+
diff --git a/source/gameengine/Physics/common/PHY_IVehicle.cpp b/source/gameengine/Physics/common/PHY_IVehicle.cpp
new file mode 100644
index 00000000000..3879e83396f
--- /dev/null
+++ b/source/gameengine/Physics/common/PHY_IVehicle.cpp
@@ -0,0 +1,7 @@
+
+#include "PHY_IVehicle.h"
+
+PHY_IVehicle::~PHY_IVehicle()
+{
+
+}
diff --git a/source/gameengine/Physics/common/PHY_IVehicle.h b/source/gameengine/Physics/common/PHY_IVehicle.h
new file mode 100644
index 00000000000..498df0dd840
--- /dev/null
+++ b/source/gameengine/Physics/common/PHY_IVehicle.h
@@ -0,0 +1,57 @@
+#ifndef PHY_IVEHICLE_H
+#define PHY_IVEHICLE_H
+
+//PHY_IVehicle provides a generic interface for (raycast based) vehicles. Mostly targetting 4 wheel cars and 2 wheel motorbikes.
+
+class PHY_IMotionState;
+#include "PHY_DynamicTypes.h"
+
+class PHY_IVehicle
+{
+public:
+
+ virtual ~PHY_IVehicle();
+
+ virtual void AddWheel(
+ PHY_IMotionState* motionState,
+ PHY__Vector3 connectionPoint,
+ PHY__Vector3 downDirection,
+ PHY__Vector3 axleDirection,
+ float suspensionRestLength,
+ float wheelRadius,
+ bool hasSteering
+ ) = 0;
+
+
+ virtual int GetNumWheels() const = 0;
+
+ virtual void GetWheelPosition(int wheelIndex,float& posX,float& posY,float& posZ) const = 0;
+ virtual void GetWheelOrientationQuaternion(int wheelIndex,float& quatX,float& quatY,float& quatZ,float& quatW) const = 0;
+ virtual float GetWheelRotation(int wheelIndex) const = 0;
+
+ virtual int GetUserConstraintId() const =0;
+ virtual int GetUserConstraintType() const =0;
+
+ //some basic steering/braking/tuning/balancing (bikes)
+
+ virtual void SetSteeringValue(float steering,int wheelIndex) = 0;
+
+ virtual void ApplyEngineForce(float force,int wheelIndex) = 0;
+
+ virtual void ApplyBraking(float braking,int wheelIndex) = 0;
+
+ virtual void SetWheelFriction(float friction,int wheelIndex) = 0;
+
+ virtual void SetSuspensionStiffness(float suspensionStiffness,int wheelIndex) = 0;
+
+ virtual void SetSuspensionDamping(float suspensionStiffness,int wheelIndex) = 0;
+
+ virtual void SetSuspensionCompression(float suspensionStiffness,int wheelIndex) = 0;
+
+ virtual void SetRollInfluence(float rollInfluence,int wheelIndex) = 0;
+
+ virtual void SetCoordinateSystem(int rightIndex,int upIndex,int forwardIndex) =0;
+
+};
+
+#endif //PHY_IVEHICLE_H
diff --git a/source/gameengine/Physics/common/PHY_Pro.h b/source/gameengine/Physics/common/PHY_Pro.h
new file mode 100644
index 00000000000..dddd93df7b4
--- /dev/null
+++ b/source/gameengine/Physics/common/PHY_Pro.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 PHY_PROPSH
+#define PHY_PROPSH
+
+#include <MT_Scalar.h>
+
+// Properties of dynamic objects
+struct PHY_ShapeProps {
+ MT_Scalar m_mass; // Total mass
+ MT_Scalar m_inertia; // Inertia, should be a tensor some time
+ MT_Scalar m_lin_drag; // Linear drag (air, water) 0 = concrete, 1 = vacuum
+ MT_Scalar m_ang_drag; // Angular drag
+ MT_Scalar m_friction_scaling[3]; // Scaling for anisotropic friction. Component in range [0, 1]
+ bool m_do_anisotropic; // Should I do anisotropic friction?
+ bool m_do_fh; // Should the object have a linear Fh spring?
+ bool m_do_rot_fh; // Should the object have an angular Fh spring?
+};
+
+
+// Properties of collidable objects (non-ghost objects)
+struct PHY_MaterialProps {
+ MT_Scalar m_restitution; // restitution of energie after a collision 0 = inelastic, 1 = elastic
+ MT_Scalar m_friction; // Coulomb friction (= ratio between the normal en maximum friction force)
+ MT_Scalar m_fh_spring; // Spring constant (both linear and angular)
+ MT_Scalar m_fh_damping; // Damping factor (linear and angular) in range [0, 1]
+ MT_Scalar m_fh_distance; // The range above the surface where Fh is active.
+ bool m_fh_normal; // Should the object slide off slopes?
+};
+
+#endif //PHY_PROPSH
+
diff --git a/source/gameengine/Physics/common/SConscript b/source/gameengine/Physics/common/SConscript
new file mode 100644
index 00000000000..91c5101675e
--- /dev/null
+++ b/source/gameengine/Physics/common/SConscript
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = 'PHY_IMotionState.cpp PHY_IPhysicsController.cpp PHY_IPhysicsEnvironment.cpp PHY_IVehicle.cpp'
+
+incs = '. ../Dummy #intern/moto/include'
+
+env.BlenderLib ( 'bf_common', Split(sources), Split(incs), [], libtype=['game', 'game2','player'], priority=[20, 35, 95] )
diff --git a/source/gameengine/PyDoc/BL_ActionActuator.py b/source/gameengine/PyDoc/BL_ActionActuator.py
new file mode 100644
index 00000000000..41f41080c31
--- /dev/null
+++ b/source/gameengine/PyDoc/BL_ActionActuator.py
@@ -0,0 +1,153 @@
+# $Id$
+# Documentation for BL_ActionActuator
+from SCA_IActuator import *
+
+class BL_ActionActuator(SCA_IActuator):
+ """
+ Action Actuators apply an action to an actor.
+ """
+ def setAction(action, reset = True):
+ """
+ Sets the current action.
+
+ @param action: The name of the action to set as the current action.
+ @type action: string
+ @param reset: Optional parameter indicating whether to reset the
+ blend timer or not. A value of 1 indicates that the
+ timer should be reset. A value of 0 will leave it
+ unchanged. If reset is not specified, the timer will
+ be reset.
+ """
+
+ def setStart(start):
+ """
+ Specifies the starting frame of the animation.
+
+ @param start: the starting frame of the animation
+ @type start: float
+ """
+
+ def setEnd(end):
+ """
+ Specifies the ending frame of the animation.
+
+ @param end: the ending frame of the animation
+ @type end: float
+ """
+ def setBlendin(blendin):
+ """
+ Specifies the number of frames of animation to generate
+ when making transitions between actions.
+
+ @param blendin: the number of frames in transition.
+ @type blendin: float
+ """
+
+ def setPriority(priority):
+ """
+ Sets the priority of this actuator.
+
+ @param priority: Specifies the new priority. Actuators will lower
+ priority numbers will override actuators with higher
+ numbers.
+ @type priority: integer
+ """
+ def setFrame(frame):
+ """
+ Sets the current frame for the animation.
+
+ @param frame: Specifies the new current frame for the animation
+ @type frame: float
+ """
+
+ def setProperty(prop):
+ """
+ Sets the property to be used in FromProp playback mode.
+
+ @param prop: the name of the property to use.
+ @type prop: string.
+ """
+
+ def setBlendtime(blendtime):
+ """
+ Sets the internal frame timer.
+
+ Allows the script to directly modify the internal timer
+ used when generating transitions between actions.
+
+ @param blendtime: The new time. This parameter must be in the range from 0.0 to 1.0.
+ @type blendtime: float
+ """
+
+ def setType(mode):
+ """
+ Sets the operation mode of the actuator
+
+ @param mode: KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND
+ @type mode: integer
+ """
+
+ def getType():
+ """
+ Returns the operation mode of the actuator
+
+ @rtype: integer
+ @return: KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND
+ """
+
+ def getAction():
+ """
+ getAction() returns the name of the action associated with this actuator.
+
+ @rtype: string
+ """
+
+ def getStart():
+ """
+ Returns the starting frame of the action.
+
+ @rtype: float
+ """
+ def getEnd():
+ """
+ Returns the last frame of the action.
+
+ @rtype: float
+ """
+ def getBlendin():
+ """
+ Returns the number of interpolation animation frames to be generated when this actuator is triggered.
+
+ @rtype: float
+ """
+ def getPriority():
+ """
+ Returns the priority for this actuator. Actuators with lower Priority numbers will
+ override actuators with higher numbers.
+
+ @rtype: integer
+ """
+ def getFrame():
+ """
+ Returns the current frame number.
+
+ @rtype: float
+ """
+ def getProperty():
+ """
+ Returns the name of the property to be used in FromProp mode.
+
+ @rtype: string
+ """
+ def setChannel(channel, matrix, mode = False):
+ """
+ @param channel: A string specifying the name of the bone channel.
+ @type channel: string
+ @param matrix: A 4x4 matrix specifying the overriding transformation
+ as an offset from the bone's rest position.
+ @type matrix: list [[float]]
+ @param mode: True for armature/world space, False for bone space
+ @type mode: boolean
+ """
+
+
diff --git a/source/gameengine/PyDoc/GameKeys.py b/source/gameengine/PyDoc/GameKeys.py
new file mode 100644
index 00000000000..268fb9cc172
--- /dev/null
+++ b/source/gameengine/PyDoc/GameKeys.py
@@ -0,0 +1,166 @@
+# $Id$
+"""
+Documentation for the GameKeys module.
+======================================
+
+This module holds key constants for the SCA_KeyboardSensor.
+
+Alphabet keys
+-------------
+ - AKEY
+ - BKEY
+ - CKEY
+ - DKEY
+ - EKEY
+ - FKEY
+ - GKEY
+ - HKEY
+ - IKEY
+ - JKEY
+ - KKEY
+ - LKEY
+ - MKEY
+ - NKEY
+ - OKEY
+ - PKEY
+ - QKEY
+ - RKEY
+ - SKEY
+ - TKEY
+ - UKEY
+ - VKEY
+ - WKEY
+ - XKEY
+ - YKEY
+ - ZKEY
+
+Number keys
+-----------
+ - ZEROKEY
+ - ONEKEY
+ - TWOKEY
+ - THREEKEY
+ - FOURKEY
+ - FIVEKEY
+ - SIXKEY
+ - SEVENKEY
+ - EIGHTKEY
+ - NINEKEY
+
+Shift Modifiers
+---------------
+ - CAPSLOCKKEY
+
+ - LEFTCTRLKEY
+ - LEFTALTKEY
+ - RIGHTALTKEY
+ - RIGHTCTRLKEY
+ - RIGHTSHIFTKEY
+ - LEFTSHIFTKEY
+
+Arrow Keys
+----------
+ - LEFTARROWKEY
+ - DOWNARROWKEY
+ - RIGHTARROWKEY
+ - UPARROWKEY
+
+Numberpad Keys
+--------------
+ - PAD0
+ - PAD1
+ - PAD2
+ - PAD3
+ - PAD4
+ - PAD5
+ - PAD6
+ - PAD7
+ - PAD8
+ - PAD9
+ - PADPERIOD
+ - PADSLASHKEY
+ - PADASTERKEY
+ - PADMINUS
+ - PADENTER
+ - PADPLUSKEY
+
+Function Keys
+-------------
+ - F1KEY
+ - F2KEY
+ - F3KEY
+ - F4KEY
+ - F5KEY
+ - F6KEY
+ - F7KEY
+ - F8KEY
+ - F9KEY
+ - F10KEY
+ - F11KEY
+ - F12KEY
+
+Other Keys
+----------
+ - ACCENTGRAVEKEY
+ - BACKSLASHKEY
+ - BACKSPACEKEY
+ - COMMAKEY
+ - DELKEY
+ - ENDKEY
+ - EQUALKEY
+ - ESCKEY
+ - HOMEKEY
+ - INSERTKEY
+ - LEFTBRACKETKEY
+ - LINEFEEDKEY
+ - MINUSKEY
+ - PAGEDOWNKEY
+ - PAGEUPKEY
+ - PAUSEKEY
+ - PERIODKEY
+ - QUOTEKEY
+ - RIGHTBRACKETKEY
+ - RETKEY
+ - SEMICOLONKEY
+ - SLASHKEY
+ - SPACEKEY
+ - TABKEY
+
+Example::
+ # Set a connected keyboard sensor to accept F1
+ import GameLogic
+ import GameKeys
+
+ co = GameLogic.getCurrentController()
+ # 'Keyboard' is a keyboard sensor
+ sensor = co.getSensor('Keyboard')
+ sensor.setKey(GameKeys.F1KEY)
+
+Example::
+ # Do the all keys thing
+ import GameLogic
+ import GameKeys
+
+ # status: these should be added to a module somewhere
+ KX_NO_INPUTSTATUS = 0
+ KX_JUSTACTIVATED = 1
+ KX_ACTIVE = 2
+ KX_JUSTRELEASED = 3
+
+ co = GameLogic.getCurrentController()
+ # 'Keyboard' is a keyboard sensor
+ sensor = co.getSensor('Keyboard')
+ keylist = sensor.getPressedKeys()
+ for key in keylist:
+ # key[0] == GameKeys.keycode, key[1] = status
+ if key[1] == KX_JUSTACTIVATED:
+ if key[0] == GameKeys.WKEY:
+ # Activate Forward!
+ if key[0] == GameKeys.SKEY:
+ # Activate Backward!
+ if key[0] == GameKeys.AKEY:
+ # Activate Left!
+ if key[0] == GameKeys.DKEY:
+ # Activate Right!
+
+"""
diff --git a/source/gameengine/PyDoc/GameLogic.py b/source/gameengine/PyDoc/GameLogic.py
new file mode 100644
index 00000000000..fcfd8bfc4eb
--- /dev/null
+++ b/source/gameengine/PyDoc/GameLogic.py
@@ -0,0 +1,223 @@
+# $Id$
+"""
+Documentation for the GameLogic Module.
+=======================================
+
+ There are only three importable modules in the game engine:
+ - GameLogic
+ - L{GameKeys}
+ - L{Rasterizer}
+
+ All the other modules are accessible through the methods in GameLogic.
+
+ See L{WhatsNew} for updates, changes and new functionality in the Game Engine Python API.
+
+ Examples::
+ # To get a controller:
+ import GameLogic
+ co = GameLogic.getCurrentController()
+
+ # To get the game object associated with this controller:
+ obj = co.getOwner()
+ L{KX_GameObject} and L{KX_Camera} or L{KX_Light} methods are
+ available depending on the type of object::
+ # To get a sensor linked to this controller.
+ # "sensorname" is the name of the sensor as defined in the Blender interface.
+ # +---------------------+ +--------+
+ # | Sensor "sensorname" +--+ Python +
+ # +---------------------+ +--------+
+ sens = co.getSensor("sensorname")
+
+ # To get a list of all sensors:
+ sensors = co.getSensors()
+
+ See the sensor's reference for available methods:
+ - L{KX_NetworkMessageSensor}
+ - L{KX_RaySensor}
+ - L{KX_MouseFocusSensor}
+ - L{KX_NearSensor}
+ - L{KX_RadarSensor}
+ - L{KX_TouchSensor}
+ - L{SCA_KeyboardSensor}
+ - L{SCA_MouseSensor}
+ - L{SCA_PropertySensor}
+ - L{SCA_RandomSensor}
+
+ You can also access actuators linked to the controller::
+ # To get an actuator attached to the controller:
+ # +--------+ +-------------------------+
+ # + Python +--+ Actuator "actuatorname" |
+ # +--------+ +-------------------------+
+ actuator = co.getActuator("actuatorname")
+
+ # Activate an actuator
+ GameLogic.addActiveActuator(actuator, True)
+
+ See the actuator's reference for available methods:
+ - L{BL_ActionActuator}
+ - L{KX_CameraActuator}
+ - L{KX_CDActuator}
+ - L{KX_ConstraintActuator}
+ - L{KX_GameActuator}
+ - L{KX_IpoActuator}
+ - L{KX_NetworkMessageActuator}
+ - L{KX_ObjectActuator}
+ - L{KX_SCA_AddObjectActuator}
+ - L{KX_SCA_EndObjectActuator}
+ - L{KX_SCA_ReplaceMeshActuator}
+ - L{KX_SceneActuator}
+ - L{KX_SoundActuator}
+ - L{KX_TrackToActuator}
+ - L{KX_VisibilityActuator}
+ - L{SCA_PropertyActuator}
+ - L{SCA_RandomActuator}
+
+ Most logic brick's methods are accessors for the properties available in the logic buttons.
+ Consult the logic bricks documentation for more information on how each logic brick works.
+
+ There are also methods to access the current L{KX_Scene}::
+ # Get the current scene
+ scene = GameLogic.getCurrentScene()
+
+ # Get the current camera
+ cam = scene.active_camera
+
+ Matricies as used by the game engine are B{row major}::
+ matrix[row][col] = blah
+ L{KX_Camera} has some examples using matricies.
+
+
+@group Constants: KX_TRUE, KX_FALSE
+@var KX_TRUE: True value used by some modules.
+@var KX_FALSE: False value used by some modules.
+
+@group Property Sensor: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL, KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED, KX_PROPSENSOR_EXPRESSION
+@var KX_PROPSENSOR_EQUAL: Activate when the property is equal to the sensor value.
+@var KX_PROPSENSOR_NOTEQUAL: Activate when the property is not equal to the sensor value.
+@var KX_PROPSENSOR_INTERVAL: Activate when the property is between the specified limits.
+@var KX_PROPSENSOR_CHANGED: Activate when the property changes
+@var KX_PROPSENSOR_EXPRESSION: Activate when the expression matches
+
+@group Constraint Actuator: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY, KX_CONSTRAINTACT_LOCZ, KX_CONSTRAINTACT_ROTX, KX_CONSTRAINTACT_ROTY, KX_CONSTRAINTACT_ROTZ
+@var KX_CONSTRAINTACT_LOCX: See L{KX_ConstraintActuator}
+@var KX_CONSTRAINTACT_LOCY: See L{KX_ConstraintActuator}
+@var KX_CONSTRAINTACT_LOCZ: See L{KX_ConstraintActuator}
+@var KX_CONSTRAINTACT_ROTX: See L{KX_ConstraintActuator}
+@var KX_CONSTRAINTACT_ROTY: See L{KX_ConstraintActuator}
+@var KX_CONSTRAINTACT_ROTZ: See L{KX_ConstraintActuator}
+
+@group IPO Actuator: KX_IPOACT_PLAY, KX_IPOACT_PINGPONG, KX_IPOACT_FLIPPER, KX_IPOACT_LOOPSTOP, KX_IPOACT_LOOPEND
+@var KX_IPOACT_PLAY: See L{KX_IpoActuator}
+@var KX_IPOACT_PINGPONG: See L{KX_IpoActuator}
+@var KX_IPOACT_FLIPPER: See L{KX_IpoActuator}
+@var KX_IPOACT_LOOPSTOP: See L{KX_IpoActuator}
+@var KX_IPOACT_LOOPEND: See L{KX_IpoActuator}
+
+@group Random Distributions: KX_RANDOMACT_BOOL_CONST, KX_RANDOMACT_BOOL_UNIFORM, KX_RANDOMACT_BOOL_BERNOUILLI, KX_RANDOMACT_INT_CONST, KX_RANDOMACT_INT_UNIFORM, KX_RANDOMACT_INT_POISSON, KX_RANDOMACT_FLOAT_CONST, KX_RANDOMACT_FLOAT_UNIFORM, KX_RANDOMACT_FLOAT_NORMAL, KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL
+@var KX_RANDOMACT_BOOL_CONST: See L{SCA_RandomActuator}
+@var KX_RANDOMACT_BOOL_UNIFORM: See L{SCA_RandomActuator}
+@var KX_RANDOMACT_BOOL_BERNOUILLI: See L{SCA_RandomActuator}
+@var KX_RANDOMACT_INT_CONST: See L{SCA_RandomActuator}
+@var KX_RANDOMACT_INT_UNIFORM: See L{SCA_RandomActuator}
+@var KX_RANDOMACT_INT_POISSON: See L{SCA_RandomActuator}
+@var KX_RANDOMACT_FLOAT_CONST: See L{SCA_RandomActuator}
+@var KX_RANDOMACT_FLOAT_UNIFORM: See L{SCA_RandomActuator}
+@var KX_RANDOMACT_FLOAT_NORMAL: See L{SCA_RandomActuator}
+@var KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: See L{SCA_RandomActuator}
+
+@group Action Actuator: KX_ACTIONACT_PLAY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND, KX_ACTIONACT_PROPERTY
+@var KX_ACTIONACT_PLAY: See L{BL_ActionActuator}
+@var KX_ACTIONACT_FLIPPER: See L{BL_ActionActuator}
+@var KX_ACTIONACT_LOOPSTOP: See L{BL_ActionActuator}
+@var KX_ACTIONACT_LOOPEND: See L{BL_ActionActuator}
+@var KX_ACTIONACT_PROPERTY: See L{BL_ActionActuator}
+
+@group Sound Actuator: KX_SOUNDACT_PLAYSTOP, KX_SOUNDACT_PLAYEND, KX_SOUNDACT_LOOPSTOP, KX_SOUNDACT_LOOPEND, KX_SOUNDACT_LOOPBIDIRECTIONAL, KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP
+@var KX_SOUNDACT_PLAYSTOP: See L{KX_SoundActuator}
+@var KX_SOUNDACT_PLAYEND: See L{KX_SoundActuator}
+@var KX_SOUNDACT_LOOPSTOP: See L{KX_SoundActuator}
+@var KX_SOUNDACT_LOOPEND: See L{KX_SoundActuator}
+@var KX_SOUNDACT_LOOPBIDIRECTIONAL: See L{KX_SoundActuator}
+@var KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: See L{KX_SoundActuator}
+"""
+
+
+def getCurrentController():
+ """
+ Gets the Python controller associated with this Python script.
+
+ @rtype: L{SCA_PythonController}
+ """
+def getCurrentScene():
+ """
+ Gets the current Scene.
+
+ @rtype: L{KX_Scene}
+ """
+def addActiveActuator(actuator, activate):
+ """
+ Activates the given actuator.
+
+ @type actuator: L{SCA_IActuator}
+ @type activate: boolean
+ @param activate: whether to activate or deactivate the given actuator.
+ """
+def getRandomFloat():
+ """
+ Returns a random floating point value in the range [0...1)
+ """
+def setGravity(gravity):
+ """
+ Sets the world gravity.
+
+ @type gravity: list [fx, fy, fz]
+ """
+def getSpectrum():
+ """
+ Returns a 512 point list from the sound card.
+ This only works if the fmod sound driver is being used.
+
+ @rtype: list [float], len(getSpectrum()) == 512
+ """
+def stopDSP():
+ """
+ Stops the sound driver using DSP effects.
+
+ Only the fmod sound driver supports this.
+ DSP can be computationally expensive.
+ """
+def getLogicTicRate():
+ """
+ Gets the logic update frequency.
+
+ @return: The logic frequency in Hz
+ @rtype: float
+ """
+def setLogicTicRate(ticrate):
+ """
+ Sets the logic update frequency.
+
+ The logic update frequency is the number of times logic bricks are executed every second.
+ The default is 30 Hz.
+
+ @param ticrate: The new logic update frequency (in Hz).
+ @type ticrate: float
+ """
+def getPhysicsTicRate():
+ """
+ Gets the physics update frequency
+
+ @return: The physics update frequency in Hz
+ @rtype: float
+ """
+def setPhysicsTicRate(ticrate):
+ """
+ Sets the physics update frequency
+
+ The physics update frequency is the number of times the physics system is executed every second.
+ The default is 60 Hz.
+
+ @param ticrate: The new update frequency (in Hz).
+ @type ticrate: float
+ """
+
diff --git a/source/gameengine/PyDoc/KX_CDActuator.py b/source/gameengine/PyDoc/KX_CDActuator.py
new file mode 100644
index 00000000000..2c202476584
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_CDActuator.py
@@ -0,0 +1,32 @@
+# $Id$
+# Documentation for CD Actuator
+from SCA_IActuator import *
+
+class KX_CDActuator(SCA_IActuator):
+ def startCD():
+ """
+ Starts the CD playing.
+ """
+ def stopCD():
+ """
+ Stops the CD playing.
+ """
+ def pauseCD():
+ """
+ Pauses the CD.
+ """
+ def setGain(gain):
+ """
+ Sets the gain (volume) of the CD.
+
+ @type gain: float
+ @param gain: the gain to set the CD to. 0.0 = silent, 1.0 = max volume.
+ """
+ def getGain():
+ """
+ Gets the current gain (volume) of the CD.
+
+ @rtype: float
+ @return: Between 0.0 (silent) and 1.0 (max volume)
+ """
+
diff --git a/source/gameengine/PyDoc/KX_Camera.py b/source/gameengine/PyDoc/KX_Camera.py
new file mode 100644
index 00000000000..4cadf1c0ed0
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_Camera.py
@@ -0,0 +1,187 @@
+# $Id$
+# Documentation for Camera game objects.
+from KX_GameObject import *
+
+class KX_Camera(KX_GameObject):
+ """
+ A Camera object.
+
+ @group Constants: INSIDE, INTERSECT, OUTSIDE
+ @ivar INSIDE: see sphereInsideFrustum() and boxInsideFrustum()
+ @ivar INTERSECT: see sphereInsideFrustum() and boxInsideFrustum()
+ @ivar OUTSIDE: see sphereInsideFrustum() and boxInsideFrustum()
+
+ @ivar lens: The camera's lens value.
+ @type lens: float
+ @ivar near: The camera's near clip distance.
+ @type near: float
+ @ivar far: The camera's far clip distance.
+ @type far: float
+ @ivar perspective: True if this camera has a perspective transform.
+
+ If perspective is False, this camera has an orthographic transform.
+
+ Note that the orthographic transform is faked by multiplying the lens attribute
+ by 100.0 and translating the camera 100.0 along the z axis.
+
+ This is the same as Blender. If you want a true orthographic transform, see L{setProjectionMatrix}.
+ @type perspective: boolean
+ @ivar frustum_culling: True if this camera is frustum culling.
+ @type frustum_culling: boolean
+ @ivar projection_matrix: This camera's 4x4 projection matrix.
+ @type projection_matrix: 4x4 Matrix [[float]]
+ @ivar modelview_matrix: This camera's 4x4 model view matrix. (read only)
+ Regenerated every frame from the camera's position and orientation.
+ @type modelview_matrix: 4x4 Matrix [[float]]
+ @ivar camera_to_world: This camera's camera to world transform. (read only)
+ Regenerated every frame from the camera's position and orientation.
+ @type camera_to_world: 4x4 Matrix [[float]]
+ @ivar world_to_camera: This camera's world to camera transform. (read only)
+ Regenerated every frame from the camera's position and orientation.
+ This is camera_to_world inverted.
+ @type world_to_camera: 4x4 Matrix [[float]]
+ """
+
+ def sphereInsideFrustum(centre, radius):
+ """
+ Tests the given sphere against the view frustum.
+
+ @param centre: The centre of the sphere (in world coordinates.)
+ @type centre: list [x, y, z]
+ @param radius: the radius of the sphere
+ @type radius: float
+ @return: INSIDE, OUTSIDE or INTERSECT
+
+ Example::
+ import GameLogic
+ co = GameLogic.getCurrentController()
+ cam = co.GetOwner()
+
+ # A sphere of radius 4.0 located at [x, y, z] = [1.0, 1.0, 1.0]
+ if (cam.sphereInsideFrustum([1.0, 1.0, 1.0], 4) != cam.OUTSIDE):
+ # Sphere is inside frustum !
+ # Do something useful !
+ else:
+ # Sphere is outside frustum
+ """
+ def boxInsideFrustum(box):
+ """
+ Tests the given box against the view frustum.
+
+ Example::
+ import GameLogic
+ co = GameLogic.getCurrentController()
+ cam = co.GetOwner()
+
+ # Box to test...
+ box = []
+ box.append([-1.0, -1.0, -1.0])
+ box.append([-1.0, -1.0, 1.0])
+ box.append([-1.0, 1.0, -1.0])
+ box.append([-1.0, 1.0, 1.0])
+ box.append([ 1.0, -1.0, -1.0])
+ box.append([ 1.0, -1.0, 1.0])
+ box.append([ 1.0, 1.0, -1.0])
+ box.append([ 1.0, 1.0, 1.0])
+
+ if (cam.boxInsideFrustum(box) != cam.OUTSIDE):
+ # Box is inside/intersects frustum !
+ # Do something useful !
+ else:
+ # Box is outside the frustum !
+
+ @return: INSIDE, OUTSIDE or INTERSECT
+ @type box: list
+ @param box: Eight (8) corner points of the box (in world coordinates.)
+ """
+ def pointInsideFrustum(point):
+ """
+ Tests the given point against the view frustum.
+
+ Example::
+ import GameLogic
+ co = GameLogic.getCurrentController()
+ cam = co.GetOwner()
+
+ # Test point [0.0, 0.0, 0.0]
+ if (cam.pointInsideFrustum([0.0, 0.0, 0.0])):
+ # Point is inside frustum !
+ # Do something useful !
+ else:
+ # Box is outside the frustum !
+
+ @rtype: boolean
+ @return: True if the given point is inside this camera's viewing frustum.
+ @type point: [x, y, z]
+ @param point: The point to test (in world coordinates.)
+ """
+ def getCameraToWorld():
+ """
+ Returns the camera-to-world transform.
+
+ @rtype: matrix (4x4 list)
+ @return: the camera-to-world transform matrix.
+ """
+ def getWorldToCamera():
+ """
+ Returns the world-to-camera transform.
+
+ This returns the inverse matrix of getCameraToWorld().
+
+ @rtype: matrix (4x4 list)
+ @return: the world-to-camera transform matrix.
+ """
+ def getProjectionMatrix():
+ """
+ Returns the camera's projection matrix.
+
+ @rtype: matrix (4x4 list)
+ @return: the camera's projection matrix.
+ """
+ def setProjectionMatrix(matrix):
+ """
+ Sets the camera's projection matrix.
+
+ You should use normalised device coordinates for the clipping planes:
+ left = -1.0, right = 1.0, top = 1.0, bottom = -1.0, near = cam.near, far = cam.far
+
+ Example::
+ import GameLogic
+
+ def Scale(matrix, size):
+ for y in range(4):
+ for x in range(4):
+ matrix[y][x] = matrix[y][x] * size[y]
+ return matrix
+
+ # Generate a perspective projection matrix
+ def Perspective(cam):
+ return [[cam.near, 0.0 , 0.0 , 0.0 ],
+ [0.0 , cam.near, 0.0 , 0.0 ],
+ [0.0 , 0.0 , -(cam.far+cam.near)/(cam.far-cam.near), -2.0*cam.far*cam.near/(cam.far - cam.near)],
+ [0.0 , 0.0 , -1.0 , 0.0 ]]
+
+ # Generate an orthographic projection matrix
+ # You will need to scale the camera
+ def Orthographic(cam):
+ return [[1.0/cam.scaling[0], 0.0 , 0.0 , 0.0 ],
+ [0.0 , 1.0/cam.scaling[1], 0.0 , 0.0 ],
+ [0.0 , 0.0 , -2.0/(cam.far-cam.near), -(cam.far+cam.near)/(cam.far-cam.near)],
+ [0.0 , 0.0 , 0.0 , 1.0 ]]
+
+ # Generate an isometric projection matrix
+ def Isometric(cam):
+ return Scale([[0.707, 0.0 , 0.707, 0.0],
+ [0.408, 0.816,-0.408, 0.0],
+ [0.0 , 0.0 , 0.0 , 0.0],
+ [0.0 , 0.0 , 0.0 , 1.0]],
+ [1.0/cam.scaling[0], 1.0/cam.scaling[1], 1.0/cam.scaling[2], 1.0])
+
+ co = GameLogic.getCurrentController()
+ cam = co.getOwner()
+ cam.setProjectionMatrix(Perspective(cam)))
+
+ @type matrix: 4x4 matrix.
+ @param matrix: The new projection matrix for this camera.
+ """
+
diff --git a/source/gameengine/PyDoc/KX_CameraActuator.py b/source/gameengine/PyDoc/KX_CameraActuator.py
new file mode 100644
index 00000000000..032fc7338ac
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_CameraActuator.py
@@ -0,0 +1,86 @@
+# $Id$
+# Documentation for KX_CameraActuator
+from SCA_IActuator import *
+
+class KX_CameraActuator(SCA_IActuator):
+ """
+ Applies changes to a camera.
+
+ @author: snail
+ """
+ def getObject():
+ """
+ Returns the name of the object this actuator tracks.
+
+ rtype: string
+ """
+
+ def setObject(target):
+ """
+ Sets the object this actuator tracks.
+
+ @param target: the object to track.
+ @type target: string or L{KX_GameObject}
+ """
+
+ def getMin():
+ """
+ Returns the minimum distance to target maintained by the actuator.
+
+ @rtype: float
+ """
+
+ def setMin(distance):
+ """
+ Sets the minimum distance to the target object maintained by the
+ actuator.
+
+ @param distance: The minimum distance to maintain.
+ @type distance: float
+ """
+
+ def getMax():
+ """
+ Gets the maximum distance to stay from the target object.
+
+ @rtype: float
+ """
+
+ def setMax(distance):
+ """
+ Sets the maximum distance to stay from the target object.
+
+ @param distance: The maximum distance to maintain.
+ @type distance: float
+ """
+
+ def getHeight():
+ """
+ Returns the height to stay above the target object.
+
+ @rtype: float
+ """
+
+ def setHeight(height):
+ """
+ Sets the height to stay above the target object.
+
+ @type height: float
+ @param height: The height to stay above the target object.
+ """
+
+ def setXY(xaxis):
+ """
+ Sets the axis to get behind.
+
+ @param xaxis: False to track Y axis, True to track X axis.
+ @type xaxis: boolean
+ """
+
+ def getXY():
+ """
+ Returns the axis this actuator is tracking.
+
+ @return: True if tracking X axis, False if tracking Y axis.
+ @rtype: boolean
+ """
diff --git a/source/gameengine/PyDoc/KX_ConstraintActuator.py b/source/gameengine/PyDoc/KX_ConstraintActuator.py
new file mode 100644
index 00000000000..9630690e572
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_ConstraintActuator.py
@@ -0,0 +1,72 @@
+# $Id$
+# Documentation for KX_ConstraintActuator
+from SCA_IActuator import *
+
+class KX_ConstraintActuator(SCA_IActuator):
+ """
+ A constraint actuator limits the position or orientation of an object.
+ """
+ def setDamp(time):
+ """
+ Sets the time this constraint is delayed.
+
+ @param time: The number of frames to delay.
+ Negative values are ignored.
+ @type time: integer
+ """
+ def getDamp():
+ """
+ Returns the damping time of the constraint.
+
+ @rtype: integer
+ """
+ def setMin(lower):
+ """
+ Sets the lower bound of the constraint.
+
+ For rotational constraints, lower is specified in degrees.
+
+ @type lower: float
+ """
+ def getMin():
+ """
+ Gets the lower bound of the constraint.
+
+ For rotational constraints, the lower bound is returned in radians.
+
+ @rtype: float
+ """
+ def setMax(upper):
+ """
+ Sets the upper bound of the constraint.
+
+ For rotational constraints, upper is specified in degrees.
+
+ @type upper: float
+ """
+ def getMax():
+ """
+ Gets the upper bound of the constraint.
+
+ For rotational constraints, the upper bound is returned in radians.
+
+ @rtype: float
+ """
+ def setLimit(limit):
+ """
+ Sets the type of constraint.
+
+ See module L{GameLogic} for valid constraint types.
+
+ @param limit: Position constraints: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY, KX_CONSTRAINTACT_LOCZ,
+ Rotation constraints: KX_CONSTRAINTACT_ROTX, KX_CONSTRAINTACT_ROTY or KX_CONSTRAINTACT_ROTZ
+ """
+ def getLimit():
+ """
+ Gets the type of constraint.
+
+ See module L{GameLogic} for valid constraints.
+
+ @return: Position constraints: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY, KX_CONSTRAINTACT_LOCZ,
+ Rotation constraints: KX_CONSTRAINTACT_ROTX, KX_CONSTRAINTACT_ROTY or KX_CONSTRAINTACT_ROTZ
+ """
diff --git a/source/gameengine/PyDoc/KX_GameActuator.py b/source/gameengine/PyDoc/KX_GameActuator.py
new file mode 100644
index 00000000000..b916b3b5617
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_GameActuator.py
@@ -0,0 +1,22 @@
+# $Id$
+# Documentation for KX_GameActuator
+from SCA_IActuator import *
+
+class KX_GameActuator(SCA_IActuator):
+ """
+ The game actuator loads a new .blend file, restarts the current .blend file or quits the game.
+ """
+ def getFile():
+ """
+ Returns the filename of the new .blend file to load.
+
+ @rtype: string
+ """
+ def setFile(filename):
+ """
+ Sets the new .blend file to load.
+
+ @param filename: The file name this actuator will load.
+ @type filename: string
+ """
+
diff --git a/source/gameengine/PyDoc/KX_GameObject.py b/source/gameengine/PyDoc/KX_GameObject.py
new file mode 100644
index 00000000000..d3428915f25
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_GameObject.py
@@ -0,0 +1,158 @@
+# $Id$
+# Documentation for game objects
+
+class KX_GameObject:
+ """
+ All game objects are derived from this class.
+
+ Properties assigned to game objects are accessible as attributes of this class.
+
+ @ivar name: The object's name.
+ @type name: string.
+ @ivar mass: The object's mass (provided the object has a physics controller). Read only.
+ @type mass: float
+ @ivar parent: The object's parent object. (Read only)
+ @type parent: L{KX_GameObject}
+ @ivar visible: visibility flag.
+ @type visible: boolean
+ @ivar position: The object's position.
+ @type position: list [x, y, z]
+ @ivar orientation: The object's orientation. 3x3 Matrix.
+ You can also write a Quaternion or Euler vector.
+ @type orientation: 3x3 Matrix [[float]]
+ @ivar scaling: The object's scaling factor. list [sx, sy, sz]
+ @type scaling: list [sx, sy, sz]
+ """
+
+ def setVisible(visible):
+ """
+ Sets the game object's visible flag.
+
+ @type visible: boolean
+ """
+ def setPosition(pos):
+ """
+ Sets the game object's position.
+
+ @type pos: [x, y, z]
+ @param pos: the new position, in world coordinates.
+ """
+ def getPosition():
+ """
+ Gets the game object's position.
+
+ @rtype: list [x, y, z]
+ @return: the object's position in world coordinates.
+ """
+ def setOrientation(orn):
+ """
+ Sets the game object's orientation.
+
+ @type orn: 3x3 rotation matrix, or Quaternion.
+ @param orn: a rotation matrix specifying the new rotation.
+ """
+ def getOrientation():
+ """
+ Gets the game object's orientation.
+
+ @rtype: 3x3 rotation matrix
+ @return: The game object's rotation matrix
+ """
+ def getLinearVelocity():
+ """
+ Gets the game object's linear velocity.
+
+ This method returns the game object's velocity through it's centre of mass,
+ ie no angular velocity component.
+
+ cf getVelocity()
+
+ @rtype: list [vx, vy, vz]
+ @return: the object's linear velocity.
+ """
+ def getVelocity(point):
+ """
+ Gets the game object's velocity at the specified point.
+
+ Gets the game object's velocity at the specified point, including angular
+ components.
+
+ @type point: list [x, y, z]
+ @param point: the point to return the velocity for, in local coordinates. (optional: default = [0, 0, 0])
+ @rtype: list [vx, vy, vz]
+ @return: the velocity at the specified point.
+ """
+ def getMass():
+ """
+ Gets the game object's mass.
+
+ @rtype: float
+ @return: the object's mass.
+ """
+ def getReactionForce():
+ """
+ Gets the game object's reaction force.
+
+ The reaction force is the force applied to this object over the last simulation timestep.
+ This also includes impulses, eg from collisions.
+
+ @rtype: list [fx, fy, fz]
+ @return: the reaction force of this object.
+ """
+ def applyImpulse(point, impulse):
+ """
+ Applies an impulse to the game object.
+
+ This will apply the specified impulse to the game object at the specified point.
+ If point != getPosition(), applyImpulse will also change the object's angular momentum.
+ Otherwise, only linear momentum will change.
+
+ @type point: list [x, y, z]
+ @param point: the point to apply the impulse to (in world coordinates)
+ """
+ def suspendDynamics():
+ """
+ Suspends physics for this object.
+ """
+ def restoreDynamics():
+ """
+ Resumes physics for this object.
+ """
+ def enableRigidBody():
+ """
+ Enables rigid body physics for this object.
+
+ Rigid body physics allows the object to roll on collisions.
+ """
+ def disableRigidBody():
+ """
+ Disables rigid body physics for this object.
+ """
+ def getParent():
+ """
+ Gets this object's parent.
+
+ @rtype: L{KX_GameObject}
+ @return: this object's parent object, or None if this object has no parent.
+ """
+ def getMesh(mesh):
+ """
+ Gets the mesh object for this object.
+
+ @type mesh: integer
+ @param mesh: the mesh object to return (optional: default mesh = 0)
+ @rtype: L{KX_MeshProxy}
+ @return: the first mesh object associated with this game object, or None if this object has no meshs.
+ """
+ def getPhysicsId():
+ """
+ Returns the user data object associated with this game object's physics controller.
+ """
+ def getDistanceTo(other):
+ """
+ Returns the distance to another object or point.
+
+ @param other: a point or another L{KX_GameObject} to measure the distance to.
+ @type other: L{KX_GameObject} or list [x, y, z]
+ @rtype: float
+ """
diff --git a/source/gameengine/PyDoc/KX_IpoActuator.py b/source/gameengine/PyDoc/KX_IpoActuator.py
new file mode 100644
index 00000000000..da8d05ddd5e
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_IpoActuator.py
@@ -0,0 +1,92 @@
+# $Id$
+# Documentation for KX_IpoActuator
+from SCA_IActuator import *
+
+class KX_IpoActuator(SCA_IActuator):
+ """
+ IPO actuator activates an animation.
+ """
+ def set(mode, startframe, endframe, force):
+ """
+ Sets the properties of the actuator.
+
+ @param mode: "Play", "PingPong", "Flipper", "LoopStop", "LoopEnd" or "FromProp"
+ @type mode: string
+ @param startframe: first frame to use
+ @type startframe: integer
+ @param endframe: last frame to use
+ @type endframe: integer
+ @param force: interpret this ipo as a force
+ @type force: boolean (KX_TRUE, KX_FALSE)
+ """
+ def setProperty(property):
+ """
+ Sets the name of the property to be used in FromProp mode.
+
+ @type property: string
+ """
+ def setStart(startframe):
+ """
+ Sets the frame from which the IPO starts playing.
+
+ @type startframe: integer
+ """
+ def getStart():
+ """
+ Returns the frame from which the IPO starts playing.
+
+ @rtype: integer
+ """
+ def setEnd(endframe):
+ """
+ Sets the frame at which the IPO stops playing.
+
+ @type endframe: integer
+ """
+ def getEnd():
+ """
+ Returns the frame at which the IPO stops playing.
+
+ @rtype: integer
+ """
+ def setIpoAsForce(force):
+ """
+ Set whether to interpret the ipo as a force rather than a displacement.
+
+ @type force: boolean
+ @param force: KX_TRUE or KX_FALSE
+ """
+ def getIpoAsForce():
+ """
+ Returns whether to interpret the ipo as a force rather than a displacement.
+
+ @rtype: boolean
+ """
+ def setType(mode):
+ """
+ Sets the operation mode of the actuator.
+
+ @param mode: KX_IPOACT_PLAY, KX_IPOACT_PINGPONG, KX_IPOACT_FLIPPER, KX_IPOACT_LOOPSTOP, KX_IPOACT_LOOPEND
+ @type mode: string
+ """
+ def getType():
+ """
+ Returns the operation mode of the actuator.
+
+ @rtype: integer
+ @return: KX_IPOACT_PLAY, KX_IPOACT_PINGPONG, KX_IPOACT_FLIPPER, KX_IPOACT_LOOPSTOP, KX_IPOACT_LOOPEND
+ """
+ def setForceIpoActsLocal(local):
+ """
+ Set whether to apply the force in the object's local
+ coordinates rather than the world global coordinates.
+
+ @param local: Apply the ipo-as-force in the object's local
+ coordinates? (KX_TRUE, KX_FALSE)
+ @type local: boolean
+ """
+ def getForceIpoActsLocal():
+ """
+ Return whether to apply the force in the object's local
+ coordinates rather than the world global coordinates.
+ """
diff --git a/source/gameengine/PyDoc/KX_Light.py b/source/gameengine/PyDoc/KX_Light.py
new file mode 100644
index 00000000000..ff0cf071d2d
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_Light.py
@@ -0,0 +1,45 @@
+# $Id$
+# Documentation for Light game objects.
+from KX_GameObject import *
+
+class KX_Light(KX_GameObject):
+ """
+ A Light object.
+
+ Example:
+
+ # Turn on a red alert light.
+ import GameLogic
+
+ co = GameLogic.getCurrentController()
+ light = co.getOwner()
+
+ light.energy = 1.0
+ light.colour = [1.0, 0.0, 0.0]
+
+ @group Constants: NORMAL, SPOT, SUN
+ @ivar SPOT: A spot light source. See attribute 'type'
+ @ivar SUN: A point light source with no attenuation. See attribute 'type'
+ @ivar NORMAL: A point light source. See attribute 'type'
+
+ @ivar type: The type of light - must be SPOT, SUN or NORMAL
+ @ivar layer: The layer mask that this light affects object on.
+ @type layer: bitfield
+ @ivar energy: The brightness of this light.
+ @type energy: float
+ @ivar distance: The maximum distance this light can illuminate. (SPOT and NORMAL lights only)
+ @type distance: float
+ @ivar colour: The colour of this light. Black = [0.0, 0.0, 0.0], White = [1.0, 1.0, 1.0]
+ @type colour: list [r, g, b]
+ @ivar color: Synonym for colour.
+ @ivar lin_attenuation: The linear component of this light's attenuation. (SPOT and NORMAL lights only)
+ @type lin_attenuation: float
+ @ivar quad_attenuation: The quadratic component of this light's attenuation (SPOT and NORMAL lights only)
+ @type quad_attenuation: float
+ @ivar spotsize: The cone angle of the spot light, in degrees. (float) (SPOT lights only)
+ 0.0 <= spotsize <= 180.0. Spotsize = 360.0 is also accepted.
+ @ivar spotblend: Specifies the intensity distribution of the spot light. (float) (SPOT lights only)
+ Higher values result in a more focused light source.
+ 0.0 <= spotblend <= 1.0.
+
+ """
diff --git a/source/gameengine/PyDoc/KX_MeshProxy.py b/source/gameengine/PyDoc/KX_MeshProxy.py
new file mode 100644
index 00000000000..e43fa3598f0
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_MeshProxy.py
@@ -0,0 +1,110 @@
+# $Id$
+# Documentation for KX_MeshProxy
+
+class KX_MeshProxy:
+ """
+ A mesh object.
+
+ You can only change the vertex properties of a mesh object, not the mesh topology.
+
+ To use mesh objects effectively, you should know a bit about how the game engine handles them.
+ 1. Mesh Objects are converted from Blender at scene load.
+ 2. The Converter groups polygons by Material. This means they can be sent to the
+ renderer efficiently. A material holds:
+ 1. The texture.
+ 2. The Blender material.
+ 3. The Tile properties
+ 4. The face properties - (From the "Texture Face" panel)
+ 5. Transparency & z sorting
+ 6. Light layer
+ 7. Polygon shape (triangle/quad)
+ 8. Game Object
+ 3. Verticies will be split by face if necessary. Verticies can only be shared between
+ faces if:
+ 1. They are at the same position
+ 2. UV coordinates are the same
+ 3. Their normals are the same (both polygons are "Set Smooth")
+ 4. They are the same colour
+ For example: a cube has 24 verticies: 6 faces with 4 verticies per face.
+
+ The correct method of iterating over every L{KX_VertexProxy} in a game object::
+ import GameLogic
+
+ co = GameLogic.getcurrentController()
+ obj = co.getOwner()
+
+ m_i = 0
+ mesh = obj.getMesh(m_i) # There can be more than one mesh...
+ while mesh != None:
+ for mat in range(mesh.getNumMaterials()):
+ for v_index in range(mesh.getVertexArrayLength(mat)):
+ vertex = mesh.getVertex(mat, v_index)
+ # Do something with vertex here...
+ # ... eg: colour the vertex red.
+ vertex.colour = [1.0, 0.0, 0.0, 1.0]
+ m_i += 1
+ mesh = obj.getMesh(m_i)
+
+
+ """
+
+ def getNumMaterials():
+ """
+ Gets the number of materials associated with this object.
+
+ @rtype: integer
+ """
+
+ def getMaterialName(matid):
+ """
+ Gets the name of the specified material.
+
+ @type matid: integer
+ @param matid: the specified material.
+ @rtype: string
+ @return: the attached material name.
+ """
+ def getTextureName(matid):
+ """
+ Gets the name of the specified material's texture.
+
+ @type matid: integer
+ @param matid: the specified material
+ @rtype: string
+ @return: the attached material's texture name.
+ """
+ def getVertexArrayLength(matid):
+ """
+ Gets the length of the vertex array associated with the specified material.
+
+ There is one vertex array for each material.
+
+ @type matid: integer
+ @param matid: the specified material
+ @rtype: integer
+ @return: the number of verticies in the vertex array.
+ """
+ def getVertex(matid, index):
+ """
+ Gets the specified vertex from the mesh object.
+
+ @type matid: integer
+ @param matid: the specified material
+ @type index: integer
+ @param index: the index into the vertex array.
+ @rtype: L{KX_VertexProxy}
+ @return: a vertex object.
+ """
+ def reinstancePhysicsMesh():
+ """
+ Updates the physics system with the changed mesh.
+
+ A mesh must have only one material with collision flags,
+ and have all collision primitives in one vertex array (ie. < 65535 verts) and
+ be either a polytope or polyheder mesh. If you don't get a warning in the
+ console when the collision type is polytope, the mesh is suitable for reinstance.
+
+ @rtype: boolean
+ @return: True if reinstance succeeded, False if it failed.
+ """
+
diff --git a/source/gameengine/PyDoc/KX_MouseFocusSensor.py b/source/gameengine/PyDoc/KX_MouseFocusSensor.py
new file mode 100644
index 00000000000..28d584037f8
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_MouseFocusSensor.py
@@ -0,0 +1,26 @@
+# $Id$
+# Documentation for KX_MouseFocusSensor
+from SCA_MouseSensor import *
+
+class KX_MouseFocusSensor(SCA_MouseSensor):
+ """
+ The mouse focus sensor detects when the mouse is over the current game object.
+
+ The mouse focus sensor works by transforming the mouse coordinates from 2d device
+ space to 3d space then raycasting away from the camera.
+ """
+
+ def GetRayTarget():
+ """
+ Returns the end point of the sensor ray.
+
+ @rtype: list [x, y, z]
+ @return: the end point of the sensor ray, in world coordinates.
+ """
+ def GetRaySource():
+ """
+ Returns the start point of the sensor ray.
+
+ @rtype: list [x, y, z]
+ @return: the start point of the sensor ray, in world coordinates.
+ """
diff --git a/source/gameengine/PyDoc/KX_NearSensor.py b/source/gameengine/PyDoc/KX_NearSensor.py
new file mode 100644
index 00000000000..fef2e4b2acc
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_NearSensor.py
@@ -0,0 +1,9 @@
+# $Id$
+# Documentation for KX_NearSensor
+from KX_TouchSensor import *
+
+class KX_NearSensor(KX_TouchSensor):
+ """
+ A near sensor is a specialised form of touch sensor.
+ """
+
diff --git a/source/gameengine/PyDoc/KX_NetworkMessageActuator.py b/source/gameengine/PyDoc/KX_NetworkMessageActuator.py
new file mode 100644
index 00000000000..aecd2897743
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_NetworkMessageActuator.py
@@ -0,0 +1,36 @@
+# $Id$
+# Documentation for KX_NetworkMessageActuator
+from SCA_IActuator import *
+
+class KX_NetworkMessageActuator(SCA_IActuator):
+ """
+ Message Actuator
+ """
+ def setToPropName(name):
+ """
+ Messages will only be sent to objects with the given property name.
+
+ @type name: string
+ """
+ def setSubject(subject):
+ """
+ Sets the subject field of the message.
+
+ @type subject: string
+ """
+ def setBodyType(bodytype):
+ """
+ Sets the type of body to send.
+
+ @type bodytype: boolean
+ @param bodytype: True to send the value of a property, False to send the body text.
+ """
+ def setBody(body):
+ """
+ Sets the message body.
+
+ @type body: string
+ @param body: if the body type is True, this is the name of the property to send.
+ if the body type is False, this is the text to send.
+ """
+
diff --git a/source/gameengine/PyDoc/KX_NetworkMessageSensor.py b/source/gameengine/PyDoc/KX_NetworkMessageSensor.py
new file mode 100644
index 00000000000..8f5f3609df7
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_NetworkMessageSensor.py
@@ -0,0 +1,43 @@
+# $Id$
+# Documentation for KX_NetworkMessageSensor
+from SCA_ISensor import *
+
+class KX_NetworkMessageSensor(SCA_ISensor):
+ """
+ The Message Sensor logic brick.
+
+ Currently only loopback (local) networks are supported.
+ """
+ def setSubjectFilterText(subject):
+ """
+ Change the message subject text that this sensor is listening to.
+
+ @type subject: string
+ @param subject: the new message subject to listen for.
+ """
+
+ def getFrameMessageCount():
+ """
+ Get the number of messages received since the last frame.
+
+ @rtype: integer
+ """
+ def getBodies():
+ """
+ Gets the list of message bodies.
+
+ @rtype: list
+ """
+ def getSubject():
+ """
+ Gets the message subject this sensor is listening for from the Subject: field.
+
+ @rtype: string
+ """
+ def getSubjects():
+ """
+ Gets the list of message subjects received.
+
+ @rtype: list
+ """
+ \ No newline at end of file
diff --git a/source/gameengine/PyDoc/KX_ObjectActuator.py b/source/gameengine/PyDoc/KX_ObjectActuator.py
new file mode 100644
index 00000000000..532c18eea5c
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_ObjectActuator.py
@@ -0,0 +1,154 @@
+# $Id$
+# Documentation for KX_ObjectActuator
+from SCA_IActuator import *
+
+class KX_ObjectActuator(SCA_IActuator):
+ """
+ The object actuator ("Motion Actuator") applies force, torque, displacement, angular displacement,
+ velocity, or angular velocity to an object.
+ """
+ def getForce():
+ """
+ Returns the force applied by the actuator.
+
+ @rtype: list [fx, fy, fz, local]
+ @return: A four item list, containing the vector force, and a flag specifying whether the force is local.
+ """
+ def setForce(fx, fy, fz, local):
+ """
+ Sets the force applied by the actuator.
+
+ @type fx: float
+ @param fx: the x component of the force.
+ @type fy: float
+ @param fy: the z component of the force.
+ @type fz: float
+ @param fz: the z component of the force.
+ @type local: boolean
+ @param local: - False: the force is applied in world coordinates.
+ - True: the force is applied in local coordinates.
+ """
+ def getTorque():
+ """
+ Returns the torque applied by the actuator.
+
+ @rtype: list [S{Tau}x, S{Tau}y, S{Tau}z, local]
+ @return: A four item list, containing the vector torque, and a flag specifying whether
+ the torque is applied in local coordinates (True) or world coordinates (False)
+ """
+ def setTorque(tx, ty, tz, local):
+ """
+ Sets the torque applied by the actuator.
+
+ @type tx: float
+ @param tx: the x component of the torque.
+ @type ty: float
+ @param ty: the z component of the torque.
+ @type tz: float
+ @param tz: the z component of the torque.
+ @type local: boolean
+ @param local: - False: the torque is applied in world coordinates.
+ - True: the torque is applied in local coordinates.
+ """
+ def getDLoc():
+ """
+ Returns the displacement vector applied by the actuator.
+
+ @rtype: list [dx, dy, dz, local]
+ @return: A four item list, containing the vector displacement, and whether
+ the displacement is applied in local coordinates (True) or world
+ coordinates (False)
+ """
+ def setDLoc(dx, dy, dz, local):
+ """
+ Sets the displacement vector applied by the actuator.
+
+ Since the displacement is applied every frame, you must adjust the displacement
+ based on the frame rate, or you game experience will depend on the player's computer
+ speed.
+
+ @type dx: float
+ @param dx: the x component of the displacement vector.
+ @type dy: float
+ @param dy: the z component of the displacement vector.
+ @type dz: float
+ @param dz: the z component of the displacement vector.
+ @type local: boolean
+ @param local: - False: the displacement vector is applied in world coordinates.
+ - True: the displacement vector is applied in local coordinates.
+ """
+ def getDRot():
+ """
+ Returns the angular displacement vector applied by the actuator.
+
+ @rtype: list [dx, dy, dz, local]
+ @return: A four item list, containing the angular displacement vector, and whether
+ the displacement is applied in local coordinates (True) or world
+ coordinates (False)
+ """
+ def setDRot(dx, dy, dz, local):
+ """
+ Sets the angular displacement vector applied by the actuator.
+
+ Since the displacement is applied every frame, you must adjust the displacement
+ based on the frame rate, or you game experience will depend on the player's computer
+ speed.
+
+ @type dx: float
+ @param dx: the x component of the angular displacement vector.
+ @type dy: float
+ @param dy: the z component of the angular displacement vector.
+ @type dz: float
+ @param dz: the z component of the angular displacement vector.
+ @type local: boolean
+ @param local: - False: the angular displacement vector is applied in world coordinates.
+ - True: the angular displacement vector is applied in local coordinates.
+ """
+ def getLinearVelocity():
+ """
+ Returns the linear velocity applied by the actuator.
+
+ @rtype: list [vx, vy, vz, local]
+ @return: A four item list, containing the vector velocity, and whether
+ the velocity is applied in local coordinates (True) or world
+ coordinates (False)
+ """
+ def setLinearVelocity(vx, vy, vz, local):
+ """
+ Sets the linear velocity applied by the actuator.
+
+ @type vx: float
+ @param vx: the x component of the velocity vector.
+ @type vy: float
+ @param vy: the z component of the velocity vector.
+ @type vz: float
+ @param vz: the z component of the velocity vector.
+ @type local: boolean
+ @param local: - False: the velocity vector is applied in world coordinates.
+ - True: the velocity vector is applied in local coordinates.
+ """
+ def getAngularVelocity():
+ """
+ Returns the angular velocity applied by the actuator.
+
+ @rtype: list [S{omega}x, S{omega}y, S{omega}z, local]
+ @return: A four item list, containing the vector velocity, and whether
+ the velocity is applied in local coordinates (True) or world
+ coordinates (False)
+ """
+ def setAngularVelocity(wx, wy, wz, local):
+ """
+ Sets the angular velocity applied by the actuator.
+
+ @type wx: float
+ @param wx: the x component of the velocity vector.
+ @type wy: float
+ @param wy: the z component of the velocity vector.
+ @type wz: float
+ @param wz: the z component of the velocity vector.
+ @type local: boolean
+ @param local: - False: the velocity vector is applied in world coordinates.
+ - True: the velocity vector is applied in local coordinates.
+ """
+
+
diff --git a/source/gameengine/PyDoc/KX_PolygonMaterial.py b/source/gameengine/PyDoc/KX_PolygonMaterial.py
new file mode 100644
index 00000000000..cfc4257f95d
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_PolygonMaterial.py
@@ -0,0 +1,281 @@
+# $Id$
+
+class KX_PolygonMaterial:
+ """
+ This is the interface to materials in the game engine.
+
+ Materials define the render state to be applied to mesh objects.
+
+ Warning: Some of the methods/variables are CObjects. If you mix these up,
+ you will crash blender.
+
+ This example requires:
+ - PyOpenGL http://pyopengl.sourceforge.net/
+ - GLEWPy http://glewpy.sourceforge.net/
+ Example::
+
+ import GameLogic
+ import OpenGL
+ from OpenGL.GL import *
+ from OpenGL.GLU import *
+ import glew
+ from glew import *
+
+ glewInit()
+
+ vertex_shader = \"\"\"
+
+ void main(void)
+ {
+ gl_Position = ftransform();
+ }
+ \"\"\"
+
+ fragment_shader =\"\"\"
+
+ void main(void)
+ {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+ \"\"\"
+
+ class MyMaterial:
+ def __init__(self):
+ self.pass_no = 0
+ # Create a shader
+ self.m_program = glCreateProgramObjectARB()
+ # Compile the vertex shader
+ self.shader(GL_VERTEX_SHADER_ARB, (vertex_shader))
+ # Compile the fragment shader
+ self.shader(GL_FRAGMENT_SHADER_ARB, (fragment_shader))
+ # Link the shaders together
+ self.link()
+
+ def PrintInfoLog(self, tag, object):
+ \"\"\"
+ PrintInfoLog prints the GLSL compiler log
+ \"\"\"
+ print "Tag: def PrintGLError(self, tag = ""):
+
+ def PrintGLError(self, tag = ""):
+ \"\"\"
+ Prints the current GL error status
+ \"\"\"
+ if len(tag):
+ print tag
+ err = glGetError()
+ if err != GL_NO_ERROR:
+ print "GL Error: %s\\n"%(gluErrorString(err))
+
+ def shader(self, type, shaders):
+ \"\"\"
+ shader compiles a GLSL shader and attaches it to the current
+ program.
+
+ type should be either GL_VERTEX_SHADER_ARB or GL_FRAGMENT_SHADER_ARB
+ shaders should be a sequence of shader source to compile.
+ \"\"\"
+ # Create a shader object
+ shader_object = glCreateShaderObjectARB(type)
+
+ # Add the source code
+ glShaderSourceARB(shader_object, len(shaders), shaders)
+
+ # Compile the shader
+ glCompileShaderARB(shader_object)
+
+ # Print the compiler log
+ self.PrintInfoLog("vertex shader", shader_object)
+
+ # Check if compiled, and attach if it did
+ compiled = glGetObjectParameterivARB(shader_object, GL_OBJECT_COMPILE_STATUS_ARB)
+ if compiled:
+ glAttachObjectARB(self.m_program, shader_object)
+
+ # Delete the object (glAttachObjectARB makes a copy)
+ glDeleteObjectARB(shader_object)
+
+ # print the gl error log
+ self.PrintGLError()
+
+ def link(self):
+ \"\"\"
+ Links the shaders together.
+ \"\"\"
+ # clear error indicator
+ glGetError()
+
+ glLinkProgramARB(self.m_program)
+
+ self.PrintInfoLog("link", self.m_program)
+
+ linked = glGetObjectParameterivARB(self.m_program, GL_OBJECT_LINK_STATUS_ARB)
+ if not linked:
+ print "Shader failed to link"
+ return
+
+ glValidateProgramARB(self.m_program)
+ valid = glGetObjectParameterivARB(self.m_program, GL_OBJECT_VALIDATE_STATUS_ARB)
+ if not valid:
+ print "Shader failed to validate"
+ return
+
+ def activate(self, rasty, cachingInfo, mat):
+ self.pass_no+=1
+ if (self.pass_no == 1):
+ glDisable(GL_COLOR_MATERIAL)
+ glUseProgramObjectARB(self.m_program)
+ return True
+
+ glEnable(GL_COLOR_MATERIAL)
+ glUseProgramObjectARB(0)
+ self.pass_no = 0
+ return False
+
+ obj = GameLogic.getCurrentController().getOwner()
+
+ mesh = obj.getMesh(0)
+
+ for mat in mesh.materials:
+ mat.setCustomMaterial(MyMaterial())
+ print mat.texture
+
+ @ivar texture: Texture name
+ @type texture: string (read only)
+
+ @ivar gl_texture: OpenGL texture handle (eg for glBindTexture(GL_TEXTURE_2D, gl_texture)
+ @type gl_texture: integer (read only)
+
+ @ivar material: Material name
+ @type material: string (read only)
+
+ @ivar tface: Texture face properties
+ @type tface: CObject (read only)
+
+ @ivar tile: Texture is tiling
+ @type tile: boolean
+ @ivar tilexrep: Number of tile repetitions in x direction.
+ @type tilexrep: integer
+ @ivar tileyrep: Number of tile repetitions in y direction.
+ @type tileyrep: integer
+
+ @ivar drawingmode: Drawing mode for the material.
+ - 2 (drawingmode & 4) Textured
+ - 4 (drawingmode & 16) Light
+ - 14 (drawingmode & 16384) 3d Polygon Text
+ @type drawingmode: bitfield
+
+ @ivar transparent: This material is transparent. All meshes with this
+ material will be rendered after non transparent meshes from back
+ to front.
+ @type transparent: boolean
+
+ @ivar zsort: Transparent polygons in meshes with this material will be sorted back to
+ front before rendering.
+ Non-Transparent polygons will be sorted front to back before rendering.
+ @type zsort: boolean
+
+ @ivar lightlayer: Light layers this material affects.
+ @type lightlayer: bitfield.
+
+ @ivar triangle: Mesh data with this material is triangles. It's probably not safe to change this.
+ @type triangle: boolean
+
+ @ivar diffuse: The diffuse colour of the material. black = [0.0, 0.0, 0.0] white = [1.0, 1.0, 1.0]
+ @type diffuse: list [r, g, b]
+ @ivar specular: The specular colour of the material. black = [0.0, 0.0, 0.0] white = [1.0, 1.0, 1.0]
+ @type specular: list [r, g, b]
+ @ivar shininess: The shininess (specular exponent) of the material. 0.0 <= shininess <= 128.0
+ @type shininess: float
+ @ivar specularity: The amount of specular of the material. 0.0 <= specularity <= 1.0
+ @type specularity: float
+ """
+ def updateTexture(tface, rasty):
+ """
+ Updates a realtime animation.
+
+ @param tface: Texture face (eg mat.tface)
+ @type tface: CObject
+ @param rasty: Rasterizer
+ @type rasty: CObject
+ """
+ def setTexture(tface):
+ """
+ Sets texture render state.
+
+ Example::
+ mat.setTexture(mat.tface)
+
+ @param tface: Texture face
+ @type tface: CObject
+ """
+ def activate(rasty, cachingInfo):
+ """
+ Sets material parameters for this object for rendering.
+
+ Material Parameters set:
+ 1. Texture
+ 2. Backface culling
+ 3. Line drawing
+ 4. Specular Colour
+ 5. Shininess
+ 6. Diffuse Colour
+ 7. Polygon Offset.
+
+ @param rasty: Rasterizer instance.
+ @type rasty: CObject
+ @param cachingInfo: Material cache instance.
+ @type cachingInfo: CObject
+ """
+ def setCustomMaterial(material):
+ """
+ Sets the material state setup object.
+
+ Using this method, you can extend or completely replace the gameengine material
+ to do your own advanced multipass effects.
+
+ Use this method to register your material class. Instead of the normal material,
+ your class's activate method will be called just before rendering the mesh.
+ This should setup the texture, material, and any other state you would like.
+ It should return True to render the mesh, or False if you are finished. You should
+ clean up any state Blender does not set before returning False.
+
+ Activate Method Definition::
+ def activate(self, rasty, cachingInfo, material):
+
+ Example::
+ class PyMaterial:
+ def __init__(self):
+ self.pass_no = -1
+
+ def activate(self, rasty, cachingInfo, material):
+ # Activate the material here.
+ #
+ # The activate method will be called until it returns False.
+ # Every time the activate method returns True the mesh will
+ # be rendered.
+ #
+ # rasty is a CObject for passing to material.updateTexture()
+ # and material.activate()
+ # cachingInfo is a CObject for passing to material.activate()
+ # material is the KX_PolygonMaterial instance this material
+ # was added to
+
+ # default material properties:
+ self.pass_no += 1
+ if self.pass_no == 0:
+ material.activate(rasty, cachingInfo)
+ # Return True to do this pass
+ return True
+
+ # clean up and return False to finish.
+ self.pass_no = -1
+ return False
+
+ # Create a new Python Material and pass it to the renderer.
+ mat.setCustomMaterial(PyMaterial())
+
+ @param material: The material object.
+ @type material: instance
+ """
+
diff --git a/source/gameengine/PyDoc/KX_RadarSensor.py b/source/gameengine/PyDoc/KX_RadarSensor.py
new file mode 100644
index 00000000000..64be858371a
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_RadarSensor.py
@@ -0,0 +1,31 @@
+# $Id$
+# Documentation for KX_RadarSensor
+from KX_NearSensor import *
+
+class KX_RadarSensor(KX_NearSensor):
+ """
+ Radar sensor is a near sensor with a conical sensor object.
+ """
+
+ def getConeOrigin():
+ """
+ Returns the origin of the cone with which to test. The origin
+ is in the middle of the cone.
+
+ @rtype: list [x, y, z]
+ """
+
+ def getConeTarget():
+ """
+ Returns the center of the bottom face of the cone with which to test.
+
+ @rtype: list [x, y, z]
+ """
+
+ def getConeHeight():
+ """
+ Returns the height of the cone with which to test.
+
+ @rtype: float
+ """
+
diff --git a/source/gameengine/PyDoc/KX_RaySensor.py b/source/gameengine/PyDoc/KX_RaySensor.py
new file mode 100644
index 00000000000..e487edcb655
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_RaySensor.py
@@ -0,0 +1,33 @@
+# $Id$
+# Documentation for KX_RaySensor
+from SCA_ISensor import *
+
+class KX_RaySensor(SCA_ISensor):
+ """
+ A ray sensor detects the first object in a given direction.
+ """
+
+ def getHitObject():
+ """
+ Returns the game object that was hit by this ray.
+
+ @rtype: KX_GameObject
+ """
+ def getHitPosition():
+ """
+ Returns the position (in worldcoordinates) where the object was hit by this ray.
+
+ @rtype: list [x, y, z]
+ """
+ def getHitNormal():
+ """
+ Returns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray.
+
+ @rtype: list [nx, ny, nz]
+ """
+ def getRayDirection():
+ """
+ Returns the direction from the ray (in worldcoordinates)
+
+ @rtype: list [dx, dy, dz]
+ """
diff --git a/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py b/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py
new file mode 100644
index 00000000000..44f9e051c8c
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py
@@ -0,0 +1,74 @@
+# $Id$
+# Documentation for KX_SCA_AddObjectActuator
+from SCA_IActuator import *
+
+class KX_SCA_AddObjectActuator(SCA_IActuator):
+ """
+ Edit Object Actuator (in Add Object Mode)
+
+ @warning: An Add Object actuator will be ignored if at game start, the linked object doesn't exist
+ (or is empty) or the linked object is in an active layer.
+
+ This will genereate a warning in the console:
+
+ C{ERROR: GameObject I{OBName} has a AddObjectActuator I{ActuatorName} without object (in 'nonactive' layer)}
+ """
+ def setObject(obj):
+ """
+ Sets the game object to add.
+
+ A copy of the object will be added to the scene when the actuator is activated.
+
+ If the object does not exist, this function is ignored.
+
+ obj can either be a L{KX_GameObject} or the name of an object.
+
+ @type obj: L{KX_GameObject} or string
+ """
+ def getObject():
+ """
+ Returns the name of the game object to be added.
+
+ Returns None if no game object has been assigned to be added.
+
+ @rtype: string
+ """
+ def setTime(time):
+ """
+ Sets the lifetime of added objects, in frames.
+
+ If time == 0, the object will last forever.
+
+ @type time: integer
+ @param time: The minimum value for time is 0.
+ """
+ def getTime():
+ """
+ Returns the lifetime of the added object, in frames.
+
+ @rtype: integer
+ """
+ def setLinearVelocity(vx, vy, vz):
+ """
+ Sets the initial linear velocity of added objects.
+
+ @type vx: float
+ @param vx: the x component of the initial linear velocity.
+ @type vy: float
+ @param vy: the y component of the initial linear velocity.
+ @type vz: float
+ @param vz: the z component of the initial linear velocity.
+ """
+ def getLinearVelocity():
+ """
+ Returns the initial linear velocity of added objects.
+
+ @rtype: list [vx, vy, vz]
+ """
+ def getLastCreatedObject():
+ """
+ Returns the last object created by this actuator.
+
+ @rtype: L{KX_GameObject}
+ @return: A L{KX_GameObject} or None if no object has been created.
+ """
diff --git a/source/gameengine/PyDoc/KX_SCA_EndObjectActuator.py b/source/gameengine/PyDoc/KX_SCA_EndObjectActuator.py
new file mode 100644
index 00000000000..8a7c79bb52b
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_SCA_EndObjectActuator.py
@@ -0,0 +1,11 @@
+# $Id$
+# Documentation for KX_SCA_EndObjectActuator
+from SCA_IActuator import *
+
+class KX_SCA_EndObjectActuator(SCA_IActuator):
+ """
+ Edit Object Actuator (in End Object mode)
+
+ This actuator has no python methods.
+ """
+
diff --git a/source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py b/source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py
new file mode 100644
index 00000000000..eb00a91a4ce
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py
@@ -0,0 +1,73 @@
+# $Id$
+# Documentation for KX_SCA_ReplaceMeshActuator
+from SCA_IActuator import *
+
+class KX_SCA_ReplaceMeshActuator(SCA_IActuator):
+ """
+ Edit Object actuator, in Replace Mesh mode.
+
+ Example::
+ # Level-of-detail
+ # Switch a game object's mesh based on its depth in the camera view.
+ # +----------+ +-----------+ +-------------------------------------+
+ # | Always +-----+ Python +-----+ Edit Object (Replace Mesh) LOD.Mesh |
+ # +----------+ +-----------+ +-------------------------------------+
+ import GameLogic
+
+ # List detail meshes here
+ # Mesh (name, near, far)
+ # Meshes overlap so that they don't 'pop' when on the edge of the distance.
+ meshes = ((".Hi", 0.0, -20.0),
+ (".Med", -15.0, -50.0),
+ (".Lo", -40.0, -100.0)
+ )
+
+ co = GameLogic.getCurrentController()
+ obj = co.getOwner()
+ act = co.getActuator("LOD." + obj.getName())
+ cam = GameLogic.getCurrentScene().active_camera
+
+ def Depth(pos, plane):
+ return pos[0]*plane[0] + pos[1]*plane[1] + pos[2]*plane[2] + plane[3]
+
+ # Depth is negative and decreasing further from the camera
+ depth = Depth(obj.position, cam.world_to_camera[2])
+
+ newmesh = None
+ curmesh = None
+ # Find the lowest detail mesh for depth
+ for mesh in meshes:
+ if depth < mesh[1] and depth > mesh[2]:
+ newmesh = mesh
+ if "ME" + obj.getName() + mesh[0] == act.getMesh():
+ curmesh = mesh
+
+ if newmesh != None and "ME" + obj.getName() + newmesh[0] != act.getMesh():
+ # The mesh is a different mesh - switch it.
+ # Check the current mesh is not a better fit.
+ if curmesh == None or curmesh[1] < depth or curmesh[2] > depth:
+ act.setMesh(obj.getName() + newmesh[0])
+ GameLogic.addActiveActuator(act, True)
+
+ @warning: Replace mesh actuators will be ignored if at game start, the
+ named mesh doesn't exist.
+
+ This will generate a warning in the console:
+
+ C{ERROR: GameObject I{OBName} ReplaceMeshActuator I{ActuatorName} without object}
+ """
+ def setMesh(name):
+ """
+ Sets the name of the mesh that will replace the current one.
+
+ @type name: string
+ """
+ def getMesh():
+ """
+ Returns the name of the mesh that will replace the current one.
+
+ Returns None if no mesh has been scheduled to be added.
+
+ @rtype: string
+ """
+
diff --git a/source/gameengine/PyDoc/KX_Scene.py b/source/gameengine/PyDoc/KX_Scene.py
new file mode 100644
index 00000000000..4a0a7a9556d
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_Scene.py
@@ -0,0 +1,70 @@
+# $Id$
+# Documentation for KX_Scene.py
+
+class KX_Scene:
+ """
+ Scene.
+
+ The activity culling stuff is supposed to disable logic bricks when their owner gets too far
+ from the active camera. It was taken from some code lurking at the back of KX_Scene - who knows
+ what it does!
+
+ Example::
+ import GameLogic
+
+ # get the scene
+ scene = GameLogic.getCurrentScene()
+
+ # print all the objects in the scene
+ for obj in scene.getObjectList():
+ print obj.getName()
+
+ # get an object named 'Cube'
+ obj = scene.getObjectList()["OBCube"]
+
+ # get the first object in the scene.
+ obj = scene.getObjectList()[0]
+
+ Example::
+ # Get the depth of an object in the camera view.
+ import GameLogic
+
+ obj = GameLogic.getCurrentController().getOwner()
+ cam = GameLogic.getCurrentScene().active_camera
+
+ # Depth is negative and decreasing further from the camera
+ depth = obj.position[0]*cam.world_to_camera[2][0] + obj.position[1]*cam.world_to_camera[2][1] + obj.position[2]*cam.world_to_camera[2][2] + cam.world_to_camera[2][3]
+
+ @bug: All attributes are read only at the moment.
+
+ @ivar name: The scene's name
+ @type name: string
+ @ivar active_camera: The current active camera
+ @type active_camera: L{KX_Camera}
+ @ivar suspended: True if the scene is suspended.
+ @type suspended: boolean
+ @ivar activity_culling: True if the scene is activity culling
+ @type activity_culling: boolean
+ @ivar activity_culling_radius: The distance outside which to do activity culling. Measured in manhattan distance.
+ @type activity_culling_radius: float
+ """
+
+ def getLightList():
+ """
+ Returns the list of lights in the scene.
+
+ @rtype: list [L{KX_Light}]
+ """
+ def getObjectList():
+ """
+ Returns the list of objects in the scene.
+
+ @rtype: list [L{KX_GameObject}]
+ """
+ def getName():
+ """
+ Returns the name of the scene.
+
+ @rtype: string
+ """
+
diff --git a/source/gameengine/PyDoc/KX_SceneActuator.py b/source/gameengine/PyDoc/KX_SceneActuator.py
new file mode 100644
index 00000000000..cfb40ae072f
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_SceneActuator.py
@@ -0,0 +1,55 @@
+# $Id$
+# Documentation for KX_SceneActuator
+from SCA_IActuator import *
+
+class KX_SceneActuator(SCA_IActuator):
+ """
+ Scene Actuator logic brick.
+
+ @warning: Scene actuators that use a scene name will be ignored if at game start, the
+ named scene doesn't exist or is empty
+
+ This will generate a warning in the console:
+
+ C{ERROR: GameObject I{OBName} has a SceneActuator I{ActuatorName} (SetScene) without scene}
+ """
+ def setUseRestart(flag):
+ """
+ Set flag to True to restart the scene.
+
+ @type flag: boolean
+ """
+ def setScene(scene):
+ """
+ Sets the name of the scene to change to/overlay/underlay/remove/suspend/resume.
+
+ @type scene: string
+ """
+ def setCamera(camera):
+ """
+ Sets the camera to change to.
+
+ Camera can be either a L{KX_Camera} or the name of the camera.
+
+ @type camera: L{KX_Camera} or string
+ """
+ def getUseRestart():
+ """
+ Returns True if the scene will be restarted.
+
+ @rtype: boolean
+ """
+ def getScene():
+ """
+ Returns the name of the scene to change to/overlay/underlay/remove/suspend/resume.
+
+ Returns an empty string ("") if no scene has been set.
+
+ @rtype: string
+ """
+ def getCamera():
+ """
+ Returns the name of the camera to change to.
+
+ @rtype: string
+ """
diff --git a/source/gameengine/PyDoc/KX_SoundActuator.py b/source/gameengine/PyDoc/KX_SoundActuator.py
new file mode 100644
index 00000000000..072af5b816c
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_SoundActuator.py
@@ -0,0 +1,145 @@
+# $Id$
+# Documentation for KX_SoundActuator
+from SCA_IActuator import *
+
+class KX_SoundActuator(SCA_IActuator):
+ """
+ Sound Actuator.
+
+ The L{startSound()}, L{pauseSound()} and L{stopSound()} do not require
+ the actuator to be activated - they act instantly.
+
+ @group Play Methods: startSound, pauseSound, stopSound
+ """
+ def setFilename(filename):
+ """
+ Sets the filename of the sound this actuator plays.
+
+ @type filename: string
+ """
+ def getFilename():
+ """
+ Returns the filename of the sound this actuator plays.
+
+ @rtype: string
+ """
+ def startSound():
+ """
+ Starts the sound.
+ """
+ def pauseSound():
+ """
+ Pauses the sound.
+ """
+ def stopSound():
+ """
+ Stops the sound.
+ """
+ def setGain(gain):
+ """
+ Sets the gain (volume) of the sound
+
+ @type gain: float
+ @param gain: 0.0 (quiet) <= gain <= 1.0 (loud)
+ """
+ def getGain():
+ """
+ Gets the gain (volume) of the sound.
+
+ @rtype: float
+ """
+ def setPitch(pitch):
+ """
+ Sets the pitch of the sound.
+
+ @type pitch: float
+ """
+ def getPitch():
+ """
+ Returns the pitch of the sound.
+
+ @rtype: float
+ """
+ def setRollOffFactor(rolloff):
+ """
+ Sets the rolloff factor for the sounds.
+
+ Rolloff defines the rate of attenuation as the sound gets further away.
+ Higher rolloff factors shorten the distance at which the sound can be heard.
+
+ @type rolloff: float
+ """
+ def getRollOffFactor():
+ """
+ Returns the rolloff factor for the sound.
+
+ @rtype: float
+ """
+ def setLooping(loop):
+ """
+ Sets the loop mode of the actuator.
+
+ @bug: There are no constants defined for this method!
+ @param loop: - Play Stop 1
+ - Play End 2
+ - Loop Stop 3
+ - Loop End 4
+ - Bidirection Stop 5
+ - Bidirection End 6
+ @type loop: integer
+ """
+ def getLooping():
+ """
+ Returns the current loop mode of the actuator.
+
+ @rtype: integer
+ """
+ def setPosition(x, y, z):
+ """
+ Sets the position this sound will come from.
+
+ @type x: float
+ @param x: The x coordinate of the sound.
+ @type y: float
+ @param y: The y coordinate of the sound.
+ @type z: float
+ @param z: The z coordinate of the sound.
+ """
+ def setVelocity(vx, vy, vz):
+ """
+ Sets the velocity this sound is moving at.
+
+ The sound's pitch is determined from the velocity.
+
+ @type vx: float
+ @param vx: The vx coordinate of the sound.
+ @type vy: float
+ @param vy: The vy coordinate of the sound.
+ @type vz: float
+ @param vz: The vz coordinate of the sound.
+ """
+ def setOrientation(o11, o12, o13, o21, o22, o23, o31, o32, o33):
+ """
+ Sets the orientation of the sound.
+
+ The nine parameters specify a rotation matrix::
+ | o11, o12, o13 |
+ | o21, o22, o23 |
+ | o31, o32, o33 |
+ """
+
+ def setType(mode):
+ """
+ Sets the operation mode of the actuator.
+
+ @param mode: KX_SOUNDACT_PLAYSTOP, KX_SOUNDACT_PLAYEND, KX_SOUNDACT_LOOPSTOP, KX_SOUNDACT_LOOPEND, KX_SOUNDACT_LOOPBIDIRECTIONAL, KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP
+ @type mode: integer
+ """
+
+ def getType():
+ """
+ Returns the operation mode of the actuator.
+
+ @rtype: integer
+ @return: KX_SOUNDACT_PLAYSTOP, KX_SOUNDACT_PLAYEND, KX_SOUNDACT_LOOPSTOP, KX_SOUNDACT_LOOPEND, KX_SOUNDACT_LOOPBIDIRECTIONAL, KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP
+ """
diff --git a/source/gameengine/PyDoc/KX_TouchSensor.py b/source/gameengine/PyDoc/KX_TouchSensor.py
new file mode 100644
index 00000000000..f2cc101af10
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_TouchSensor.py
@@ -0,0 +1,50 @@
+# $Id$
+# Documentation for KX_TouchSensor
+from SCA_ISensor import *
+
+class KX_TouchSensor(SCA_ISensor):
+ """
+ Touch sensor detects collisions between objects.
+ """
+ def setProperty(name):
+ """
+ Set the property or material to collide with. Use
+ setTouchMaterial() to switch between properties and
+ materials.
+ @type name: string
+ """
+ def getProperty():
+ """
+ Returns the property or material to collide with. Use
+ getTouchMaterial() to find out whether this sensor
+ looks for properties or materials.
+
+ @rtype: string
+ """
+
+ def getHitObject():
+ """
+ Returns the last object hit by this touch sensor.
+
+ @rtype: L{KX_GameObject}
+ """
+ def getHitObjectList():
+ """
+ Returns a list of all objects hit in the last frame.
+
+ Only objects that have the requisite material/property are listed.
+
+ @rtype: list [L{KX_GameObject}]
+ """
+ def getTouchMaterial():
+ """
+ Returns KX_TRUE if this sensor looks for a specific material,
+ KX_FALSE if it looks for a specific property.
+ """
+ def setTouchMaterial(flag):
+ """
+ Set flag to KX_TRUE to switch on positive pulse mode,
+ KX_FALSE to switch off positive pulse mode.
+
+ @type flag: KX_TRUE or KX_FALSE.
+ """
diff --git a/source/gameengine/PyDoc/KX_TrackToActuator.py b/source/gameengine/PyDoc/KX_TrackToActuator.py
new file mode 100644
index 00000000000..39fb99ec2e2
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_TrackToActuator.py
@@ -0,0 +1,57 @@
+# $Id$
+# Documentation for KX_TrackToActuator
+from SCA_IActuator import *
+
+class KX_TrackToActuator(SCA_IActuator):
+ """
+ Edit Object actuator in Track To mode.
+
+ @warning: Track To Actuators will be ignored if at game start, the
+ object to track to is invalid.
+
+ This will generate a warning in the console:
+
+ C{ERROR: GameObject I{OBName} no object in EditObjectActuator I{ActuatorName}}
+
+ """
+ def setObject(object):
+ """
+ Sets the object to track.
+
+ @type object: L{KX_GameObject} or string
+ @param object: Either a reference to a game object or the name of the object to track.
+ """
+ def getObject():
+ """
+ Returns the name of the object to track.
+
+ Returns None if no object has been set to track.
+
+ @rtype: string
+ """
+ def setTime(time):
+ """
+ Sets the time in frames with which to delay the tracking motion.
+
+ @type time: integer
+ """
+ def getTime():
+ """
+ Returns the time in frames with which the tracking motion is delayed.
+
+ @rtype: integer
+ """
+ def setUse3D(use3d):
+ """
+ Sets the tracking motion to use 3D.
+
+ @type use3d: boolean
+ @param use3d: - True: allow the tracking motion to extend in the z-direction.
+ - False: lock the tracking motion to the x-y plane.
+ """
+ def getUse3D():
+ """
+ Returns True if the tracking motion will track in the z direction.
+
+ @rtype: boolean
+ """
diff --git a/source/gameengine/PyDoc/KX_VertexProxy.py b/source/gameengine/PyDoc/KX_VertexProxy.py
new file mode 100644
index 00000000000..8dc2752c037
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_VertexProxy.py
@@ -0,0 +1,122 @@
+# $Id$
+# Documentation for the vertex proxy class
+
+class KX_VertexProxy:
+ """
+ A vertex holds position, UV, colour and normal information.
+
+ Note:
+ The physics simulation is NOT currently updated - physics will not respond
+ to changes in the vertex position.
+
+ @ivar XYZ: The position of the vertex.
+ @type XYZ: list [x, y, z]
+ @ivar UV: The texture coordinates of the vertex.
+ @type UV: list [u, v]
+ @ivar normal: The normal of the vertex
+ @type normal: list [nx, ny, nz]
+ @ivar colour: The colour of the vertex.
+ Black = [0.0, 0.0, 0.0, 1.0], White = [1.0, 1.0, 1.0, 1.0]
+ @type colour: list [r, g, b, a]
+ @ivar color: Synonym for colour.
+
+ @group Position: x, y, z
+ @ivar x: The x coordinate of the vertex.
+ @type x: float
+ @ivar y: The y coordinate of the vertex.
+ @type y: float
+ @ivar z: The z coordinate of the vertex.
+ @type z: float
+
+ @group Texture Coordinates: u, v
+ @ivar u: The u texture coordinate of the vertex.
+ @type u: float
+ @ivar v: The v texture coordinate of the vertex.
+ @type v: float
+
+ @group Colour: r, g, b, a
+ @ivar r: The red component of the vertex colour. 0.0 <= r <= 1.0
+ @type r: float
+ @ivar g: The green component of the vertex colour. 0.0 <= g <= 1.0
+ @type g: float
+ @ivar b: The blue component of the vertex colour. 0.0 <= b <= 1.0
+ @type b: float
+ @ivar a: The alpha component of the vertex colour. 0.0 <= a <= 1.0
+ @type a: float
+ """
+
+ def getXYZ():
+ """
+ Gets the position of this vertex.
+
+ @rtype: list [x, y, z]
+ @return: this vertexes position in local coordinates.
+ """
+ def setXYZ(pos):
+ """
+ Sets the position of this vertex.
+
+ @type pos: list [x, y, z]
+ @param pos: the new position for this vertex in local coordinates.
+ """
+ def getUV():
+ """
+ Gets the UV (texture) coordinates of this vertex.
+
+ @rtype: list [u, v]
+ @return: this vertexes UV (texture) coordinates.
+ """
+ def setUV(uv):
+ """
+ Sets the UV (texture) coordinates of this vertex.
+
+ @type uv: list [u, v]
+ """
+ def getRGBA():
+ """
+ Gets the colour of this vertex.
+
+ The colour is represented as four bytes packed into an integer value. The colour is
+ packed as RGBA.
+
+ Since Python offers no way to get each byte without shifting, you must use the struct module to
+ access colour in an machine independent way.
+
+ Because of this, it is suggested you use the r, g, b and a attributes or the colour attribute instead.
+
+ Example::
+ import struct;
+ col = struct.unpack('4B', struct.pack('I', v.getRGBA()))
+ # col = (r, g, b, a)
+ # black = ( 0, 0, 0, 255)
+ # white = (255, 255, 255, 255)
+
+ @rtype: integer
+ @return: packed colour. 4 byte integer with one byte per colour channel in RGBA format.
+ """
+ def setRGBA(col):
+ """
+ Sets the colour of this vertex.
+
+ See getRGBA() for the format of col, and its relevant problems. Use the r, g, b and a attributes
+ or the colour attribute instead.
+
+ setRGBA() also accepts a four component list as argument col. The list represents the colour as [r, g, b, a]
+ with black = [0.0, 0.0, 0.0, 1.0] and white = [1.0, 1.0, 1.0, 1.0]
+
+ Example::
+ v.setRGBA(0xff0000ff) # Red
+ v.setRGBA(0xff00ff00) # Green on little endian, transparent purple on big endian
+ v.setRGBA([1.0, 0.0, 0.0, 1.0]) # Red
+ v.setRGBA([0.0, 1.0, 0.0, 1.0]) # Green on all platforms.
+
+ @type col: integer or list [r, g, b, a]
+ @param col: the new colour of this vertex in packed RGBA format.
+ """
+ def getNormal():
+ """
+ Gets the normal vector of this vertex.
+
+ @rtype: list [nx, ny, nz]
+ @return: normalised normal vector.
+ """
diff --git a/source/gameengine/PyDoc/KX_VisibilityActuator.py b/source/gameengine/PyDoc/KX_VisibilityActuator.py
new file mode 100644
index 00000000000..22499f25d81
--- /dev/null
+++ b/source/gameengine/PyDoc/KX_VisibilityActuator.py
@@ -0,0 +1,17 @@
+# $Id$
+# Documentation for KX_VisibilityActuator
+from SCA_IActuator import *
+
+class KX_VisibilityActuator(SCA_IActuator):
+ """
+ Visibility Actuator.
+ """
+ def set(visible):
+ """
+ Sets whether the actuator makes its parent object visible or invisible.
+
+ @param visible: - True: Makes its parent visible.
+ - False: Makes its parent invisible.
+ """
+
+ \ No newline at end of file
diff --git a/source/gameengine/PyDoc/Makefile b/source/gameengine/PyDoc/Makefile
new file mode 100644
index 00000000000..7861894ddec
--- /dev/null
+++ b/source/gameengine/PyDoc/Makefile
@@ -0,0 +1,13 @@
+
+
+SOURCES=$(shell ls *.py)
+TARGETS:=$(SOURCES:.py=.html)
+PYDOC=/usr/lib/python2.2/pydoc.py
+
+all: $(SOURCES)
+ epydoc -o BPY_GE_236 --url "http://www.blender.org" -t GameLogic.py \
+ -n "Blender GameEngine" --no-private --no-frames \
+ $(shell ls *.py )
+
+clean:
+ rm *.html
diff --git a/source/gameengine/PyDoc/Rasterizer.py b/source/gameengine/PyDoc/Rasterizer.py
new file mode 100644
index 00000000000..f0e48b6ed43
--- /dev/null
+++ b/source/gameengine/PyDoc/Rasterizer.py
@@ -0,0 +1,147 @@
+# $Id$
+"""
+Documentation for the Rasterizer module.
+
+Example Uses an L{SCA_MouseSensor}, and two L{KX_ObjectActuator}s to implement MouseLook::
+ # To use a mouse movement sensor "Mouse" and a
+ # motion actuator to mouse look:
+ import Rasterizer
+ import GameLogic
+
+ # SCALE sets the speed of motion
+ SCALE=[1, 0.5]
+
+ co = GameLogic.getCurrentController()
+ obj = co.getOwner()
+ mouse = co.getSensor("Mouse")
+ lmotion = co.getActuator("LMove")
+ wmotion = co.getActuator("WMove")
+
+ # Transform the mouse coordinates to see how far the mouse has moved.
+ def mousePos():
+ x = (Rasterizer.getWindowWidth()/2 - mouse.getXPosition())*SCALE[0]
+ y = (Rasterizer.getWindowHeight()/2 - mouse.getYPosition())*SCALE[1]
+ return (x, y)
+
+ pos = mousePos()
+
+ # Set the amount of motion: X is applied in world coordinates...
+ lmotion.setTorque(0.0, 0.0, pos[0], False)
+ # ...Y is applied in local coordinates
+ wmotion.setTorque(-pos[1], 0.0, 0.0, True)
+
+ # Activate both actuators
+ GameLogic.addActiveActuator(lmotion, True)
+ GameLogic.addActiveActuator(wmotion, True)
+
+ # Centre the mouse
+ Rasterizer.setMousePosition(Rasterizer.getWindowWidth()/2, Rasterizer.getWindowHeight()/2)
+
+
+"""
+
+def getWindowWidth():
+ """
+ Gets the width of the window (in pixels)
+
+ @rtype: integer
+ """
+def getWindowHeight():
+ """
+ Gets the height of the window (in pixels)
+
+ @rtype: integer
+ """
+def makeScreenshot(filename):
+ """
+ Writes a screenshot to the given filename.
+
+ If filename starts with // the image will be saved relative to the current directory.
+ If the filename contains # it will be replaced with the frame number.
+
+ The standalone player saves .png files. It does not support colour space conversion
+ or gamma correction.
+
+ When run from Blender, makeScreenshot supports Iris, IrisZ, TGA, Raw TGA, PNG, HamX, and Jpeg.
+ Gamma, Colourspace conversion and Jpeg compression are taken from the Render settings panels.
+
+ @type filename: string
+ """
+
+def enableVisibility(visible):
+ """
+ Doesn't really do anything...
+ """
+
+def showMouse(visible):
+ """
+ Enables or disables the operating system mouse cursor.
+
+ @type visible: boolean
+ """
+
+def setMousePosition(x, y):
+ """
+ Sets the mouse cursor position.
+
+ @type x, y: integer
+ """
+
+def setBackgroundColor(rgba):
+ """
+ Sets the window background colour.
+
+ @type rgba: list [r, g, b, a]
+ """
+
+def setMistColor(rgb):
+ """
+ Sets the mist colour.
+
+ @type rgb: list [r, g, b]
+ """
+
+def setMistStart(start):
+ """
+ Sets the mist start value. Objects further away than start will have mist applied to them.
+
+ @type start: float
+ """
+
+def setMistEnd(end):
+ """
+ Sets the mist end value. Objects further away from this will be coloured solid with
+ the colour set by setMistColor().
+
+ @type end: float
+ """
+
+def setEyeSeparation(eyesep):
+ """
+ Sets the eye separation for stereo mode.
+
+ @param eyesep: The distance between the left and right eye.
+ @type eyesep: float
+ """
+
+def getEyeSeparation():
+ """
+ Gets the current eye separation for stereo mode.
+
+ @rtype: float
+ """
+
+def setFocalLength(focallength):
+ """
+ Sets the focal length for stereo mode.
+
+ @param focallength: The focal length.
+ @type focallength: float
+ """
+
+def getFocalLength():
+ """
+ Gets the current focal length for stereo mode.
+
+ @rtype: float
+ """
diff --git a/source/gameengine/PyDoc/SCA_ANDController.py b/source/gameengine/PyDoc/SCA_ANDController.py
new file mode 100644
index 00000000000..1717e613595
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_ANDController.py
@@ -0,0 +1,11 @@
+# $Id$
+# Documentation for SCA_ANDController
+from SCA_IController import *
+
+class SCA_ANDController(SCA_IController):
+ """
+ An AND controller activates only when all linked sensors are activated.
+
+ There are no special python methods for this controller.
+ """
+
diff --git a/source/gameengine/PyDoc/SCA_AlwaysSensor.py b/source/gameengine/PyDoc/SCA_AlwaysSensor.py
new file mode 100644
index 00000000000..54ab07a8a99
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_AlwaysSensor.py
@@ -0,0 +1,9 @@
+# $Id$
+# Documentation for SCA_AlwaysSensor
+from SCA_ISensor import *
+
+class SCA_AlwaysSensor(SCA_ISensor):
+ """
+ This sensor is always activated.
+ """
+
diff --git a/source/gameengine/PyDoc/SCA_IActuator.py b/source/gameengine/PyDoc/SCA_IActuator.py
new file mode 100644
index 00000000000..ac47c15dc78
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_IActuator.py
@@ -0,0 +1,9 @@
+# $Id$
+# Documentation for SCA_IActuator
+from SCA_ILogicBrick import *
+
+class SCA_IActuator(SCA_ILogicBrick):
+ """
+ Base class for all actuator logic bricks.
+ """
+
diff --git a/source/gameengine/PyDoc/SCA_IController.py b/source/gameengine/PyDoc/SCA_IController.py
new file mode 100644
index 00000000000..f83e7c97dce
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_IController.py
@@ -0,0 +1,9 @@
+# $Id$
+# Documentation for KX_CameraActuator
+from SCA_ILogicBrick import *
+
+class SCA_IController(SCA_ILogicBrick):
+ """
+ Base class for all controller logic bricks.
+ """
+
diff --git a/source/gameengine/PyDoc/SCA_ILogicBrick.py b/source/gameengine/PyDoc/SCA_ILogicBrick.py
new file mode 100644
index 00000000000..ea09fcaea37
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_ILogicBrick.py
@@ -0,0 +1,32 @@
+# $Id$
+# Documentation for the logic brick base class SCA_ILogicBrick
+from KX_GameObject import *
+
+class SCA_ILogicBrick:
+ """
+ Base class for all logic bricks.
+ """
+
+ def getOwner():
+ """
+ Gets the game object associated with this logic brick.
+
+ @rtype: L{KX_GameObject}
+ """
+ def setExecutePriority(priority):
+ """
+ Sets the priority of this logic brick.
+
+ This determines the order controllers are evaluated, and actuators are activated.
+ Bricks with lower priority will be executed first.
+
+ @type priority: integer
+ @param priority: the priority of this logic brick.
+ """
+ def getExecutePriority():
+ """
+ Gets the execution priority of this logic brick.
+
+ @rtype: integer
+ @return: this logic bricks current priority.
+ """
diff --git a/source/gameengine/PyDoc/SCA_ISensor.py b/source/gameengine/PyDoc/SCA_ISensor.py
new file mode 100644
index 00000000000..b96d8c8c075
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_ISensor.py
@@ -0,0 +1,62 @@
+# $Id$
+# Documentation for SCA_ISensor
+from SCA_ILogicBrick import *
+
+class SCA_ISensor(SCA_ILogicBrick):
+ """
+ Base class for all sensor logic bricks.
+ """
+
+ def isPositive():
+ """
+ True if this sensor brick has been activated.
+ """
+
+ def getUsePosPulseMode():
+ """
+ True if the sensor is in positive pulse mode.
+ """
+ def setUsePosPulseMode(pulse):
+ """
+ Sets positive pulse mode.
+
+ @type pulse: boolean
+ @param pulse: If True, will activate positive pulse mode for this sensor.
+ """
+ def getFrequency():
+ """
+ The frequency for pulse mode sensors.
+
+ @rtype: integer
+ @return: the pulse frequency in 1/50 sec.
+ """
+ def setFrequency(freq):
+ """
+ Sets the frequency for pulse mode sensors.
+
+ @type freq: integer
+ @return: the pulse frequency in 1/50 sec.
+ """
+ def getUseNegPulseMode():
+ """
+ True if the sensor is in negative pulse mode.
+ """
+ def setUseNegPulseMode(pulse):
+ """
+ Sets negative pulse mode.
+
+ @type pulse: boolean
+ @param pulse: If True, will activate negative pulse mode for this sensor.
+ """
+ def getInvert():
+ """
+ True if this sensor activates on negative events.
+ """
+ def setInvert(invert):
+ """
+ Sets if this sensor activates on positive or negative events.
+
+ @type invert: boolean
+ @param invert: true if activates on negative events; false if activates on positive events.
+ """
+
diff --git a/source/gameengine/PyDoc/SCA_KeyboardSensor.py b/source/gameengine/PyDoc/SCA_KeyboardSensor.py
new file mode 100644
index 00000000000..2f741f7d6a2
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_KeyboardSensor.py
@@ -0,0 +1,58 @@
+# $Id$
+# Documentation for SCA_KeyboardSensor
+from SCA_ISensor import *
+
+class SCA_KeyboardSensor(SCA_ISensor):
+ """
+ A keyboard sensor detects player key presses.
+
+ See module L{GameKeys} for keycode values.
+ """
+
+ def getKey():
+ """
+ Returns the key code this sensor is looking for.
+ """
+
+ def setKey(keycode):
+ """
+ Set the key this sensor should listen for.
+
+ @type keycode: keycode from L{GameKeys} module
+ """
+
+ def getHold1():
+ """
+ Returns the key code for the first modifier this sensor is looking for.
+ """
+
+ def setHold1():
+ """
+ Sets the key code for the first modifier this sensor should look for.
+ """
+
+ def getHold2():
+ """
+ Returns the key code for the second modifier this sensor is looking for.
+ """
+
+ def setHold2():
+ """
+ Sets the key code for the second modifier this sensor should look for.
+ """
+
+ def getPressedKeys():
+ """
+ Get a list of keys that have either been pressed, or just released this frame.
+
+ @rtype: list of key status. [[keycode, status]]
+ """
+
+ def getCurrentlyPressedKeys():
+ """
+ Get a list of currently pressed keys that have either been pressed, or just released
+
+ @rtype: list of key status. [[keycode, status]]
+ """
+
+
diff --git a/source/gameengine/PyDoc/SCA_MouseSensor.py b/source/gameengine/PyDoc/SCA_MouseSensor.py
new file mode 100644
index 00000000000..06b261f67fa
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_MouseSensor.py
@@ -0,0 +1,23 @@
+# $Id$
+# Documentation for SCA_MouseSensor
+from SCA_ISensor import *
+
+class SCA_MouseSensor(SCA_ISensor):
+ """
+ Mouse Sensor logic brick.
+ """
+
+ def getXPosition():
+ """
+ Gets the x coordinate of the mouse.
+
+ @rtype: integer
+ @return: the current x coordinate of the mouse, in frame coordinates (pixels)
+ """
+ def getYPosition():
+ """
+ Gets the y coordinate of the mouse.
+
+ @rtype: integer
+ @return: the current y coordinate of the mouse, in frame coordinates (pixels).
+ """
diff --git a/source/gameengine/PyDoc/SCA_ORController.py b/source/gameengine/PyDoc/SCA_ORController.py
new file mode 100644
index 00000000000..eeeb9de3afe
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_ORController.py
@@ -0,0 +1,11 @@
+# $Id$
+# Documentation for SCA_ORController
+from SCA_IController import *
+
+class SCA_ORController(SCA_IController):
+ """
+ An OR controller activates when any connected sensor activates.
+
+ There are no special python methods for this controller.
+ """
+
diff --git a/source/gameengine/PyDoc/SCA_PropertyActuator.py b/source/gameengine/PyDoc/SCA_PropertyActuator.py
new file mode 100644
index 00000000000..dc1233ddfb7
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_PropertyActuator.py
@@ -0,0 +1,38 @@
+# $Id$
+# Documentation for SCA_PropertyActuator
+from SCA_IActuator import *
+
+class SCA_PropertyActuator(SCA_IActuator):
+ """
+ Property Actuator
+ """
+ def setProperty(prop):
+ """
+ Set the property on which to operate.
+
+ If there is no property of this name, the call is ignored.
+
+ @type prop: string
+ @param prop: The name of the property to set.
+ """
+ def getProperty():
+ """
+ Returns the name of the property on which to operate.
+
+ @rtype: string
+ """
+ def setValue(value):
+ """
+ Set the value with which the actuator operates.
+
+ If the value is not compatible with the type of the
+ property, the subsequent action is ignored.
+
+ @type value: string
+ """
+ def getValue():
+ """
+ Gets the value with which this actuator operates.
+
+ @rtype: string
+ """
diff --git a/source/gameengine/PyDoc/SCA_PropertySensor.py b/source/gameengine/PyDoc/SCA_PropertySensor.py
new file mode 100644
index 00000000000..22de8d8b986
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_PropertySensor.py
@@ -0,0 +1,57 @@
+# $Id$
+# Documentation for SCA_PropertySensor
+from SCA_ISensor import *
+
+class SCA_PropertySensor(SCA_ISensor):
+ """
+ Activates when the game object property matches.
+ """
+
+ def getType():
+ """
+ Gets when to activate this sensor.
+
+ @return: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL,
+ KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED,
+ or KX_PROPSENSOR_EXPRESSION.
+ """
+
+ def setType(checktype):
+ """
+ Set the type of check to perform.
+
+ @type checktype: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL,
+ KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED,
+ or KX_PROPSENSOR_EXPRESSION.
+ """
+
+ def getProperty():
+ """
+ Return the property with which the sensor operates.
+
+ @rtype: string
+ @return: the name of the property this sensor is watching.
+ """
+ def setProperty(name):
+ """
+ Sets the property with which to operate. If there is no property
+ of that name, this call is ignored.
+
+ @type name: string.
+ """
+ def getValue():
+ """
+ Return the value with which the sensor compares to the value of the property.
+
+ @rtype: string
+ @return: the value of the property this sensor is watching.
+ """
+ def setValue(value):
+ """
+ Set the value with which the sensor operates. If the value
+ is not compatible with the type of the property, the subsequent
+ action is ignored.
+
+ @type value: string
+ """
+
diff --git a/source/gameengine/PyDoc/SCA_PythonController.py b/source/gameengine/PyDoc/SCA_PythonController.py
new file mode 100644
index 00000000000..eb9e57c0819
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_PythonController.py
@@ -0,0 +1,49 @@
+# $Id$
+# Documentation for SCA_PythonController
+from SCA_IController import *
+
+class SCA_PythonController(SCA_IController):
+ """
+ A Python controller uses a Python script to activate it's actuators,
+ based on it's sensors.
+ """
+
+ def getSensors():
+ """
+ Gets a list of all sensors attached to this controller.
+
+ @rtype: list [L{SCA_ISensor}]
+ """
+ def getSensor(name):
+ """
+ Gets the named linked sensor.
+
+ @type name: string
+ @rtype: L{SCA_ISensor}
+ """
+ def getActuators():
+ """
+ Gets a list of all actuators linked to this controller.
+
+ @rtype: list [L{SCA_IActuator}]
+ """
+ def getActuator(name):
+ """
+ Gets the named linked actuator.
+
+ @type name: string
+ @rtype: L{SCA_IActuator}
+ """
+ def getScript():
+ """
+ Gets the Python script this controller executes.
+
+ @rtype: string
+ """
+ def setScript(script):
+ """
+ Sets the Python script this controller executes.
+
+ @type script: string.
+ """
+
diff --git a/source/gameengine/PyDoc/SCA_RandomActuator.py b/source/gameengine/PyDoc/SCA_RandomActuator.py
new file mode 100644
index 00000000000..353b398b1ff
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_RandomActuator.py
@@ -0,0 +1,143 @@
+# $Id$
+# Documentation for SCA_RandomActuator
+from SCA_IActuator import *
+
+class SCA_RandomActuator(SCA_IActuator):
+ """
+ Random Actuator
+ """
+ def setSeed(seed):
+ """
+ Sets the seed of the random number generator.
+
+ Equal seeds produce equal series. If the seed is 0,
+ the generator will produce the same value on every call.
+
+ @type seed: integer
+ """
+ def getSeed():
+ """
+ Returns the initial seed of the generator.
+
+ @rtype: integer
+ """
+ def getPara1():
+ """
+ Returns the first parameter of the active distribution.
+
+ Refer to the documentation of the generator types for the meaning
+ of this value.
+
+ @rtype: float
+ """
+ def getPara2():
+ """
+ Returns the second parameter of the active distribution.
+
+ Refer to the documentation of the generator types for the meaning
+ of this value.
+
+ @rtype: float
+ """
+ def getDistribution():
+ """
+ Returns the type of random distribution.
+
+ @rtype: distribution type
+ @return: KX_RANDOMACT_BOOL_CONST, KX_RANDOMACT_BOOL_UNIFORM, KX_RANDOMACT_BOOL_BERNOUILLI,
+ KX_RANDOMACT_INT_CONST, KX_RANDOMACT_INT_UNIFORM, KX_RANDOMACT_INT_POISSON,
+ KX_RANDOMACT_FLOAT_CONST, KX_RANDOMACT_FLOAT_UNIFORM, KX_RANDOMACT_FLOAT_NORMAL,
+ KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL
+ """
+ def setProperty(property):
+ """
+ Set the property to which the random value is assigned.
+
+ If the generator and property types do not match, the assignment is ignored.
+
+ @type property: string
+ @param property: The name of the property to set.
+ """
+ def getProperty():
+ """
+ Returns the name of the property to set.
+
+ @rtype: string
+ """
+ def setBoolConst(value):
+ """
+ Sets this generator to produce a constant boolean value.
+
+ @param value: The value to return.
+ @type value: boolean
+ """
+ def setBoolUniform():
+ """
+ Sets this generator to produce a uniform boolean distribution.
+
+ The generator will generate True or False with 50% chance.
+ """
+ def setBoolBernouilli(value):
+ """
+ Sets this generator to produce a Bernouilli distribution.
+
+ @param value: Specifies the proportion of False values to produce.
+ - 0.0: Always generate True
+ - 1.0: Always generate False
+ @type value: float
+ """
+ def setIntConst(value):
+ """
+ Sets this generator to always produce the given value.
+
+ @param value: the value this generator produces.
+ @type value: integer
+ """
+ def setIntUniform(lower_bound, upper_bound):
+ """
+ Sets this generator to produce a random value between the given lower and
+ upper bounds (inclusive).
+
+ @type lower_bound: integer
+ @type upper_bound: integer
+ """
+ def setIntPoisson(value):
+ """
+ Generate a Poisson-distributed number.
+
+ This performs a series of Bernouilli tests with parameter value.
+ It returns the number of tries needed to achieve succes.
+
+ @type value: float
+ """
+ def setFloatConst(value):
+ """
+ Always generate the given value.
+
+ @type value: float
+ """
+ def setFloatUniform(lower_bound, upper_bound):
+ """
+ Generates a random float between lower_bound and upper_bound with a
+ uniform distribution.
+
+ @type lower_bound: float
+ @type upper_bound: float
+ """
+ def setFloatNormal(mean, standard_deviation):
+ """
+ Generates a random float from the given normal distribution.
+
+ @type mean: float
+ @param mean: The mean (average) value of the generated numbers
+ @type standard_deviation: float
+ @param standard_deviation: The standard deviation of the generated numbers.
+ """
+ def setFloatNegativeExponential(half_life):
+ """
+ Generate negative-exponentially distributed numbers.
+
+ The half-life 'time' is characterized by half_life.
+
+ @type half_life: float
+ """
diff --git a/source/gameengine/PyDoc/SCA_RandomSensor.py b/source/gameengine/PyDoc/SCA_RandomSensor.py
new file mode 100644
index 00000000000..940b8f879ff
--- /dev/null
+++ b/source/gameengine/PyDoc/SCA_RandomSensor.py
@@ -0,0 +1,28 @@
+# $Id$
+# Documentation for SCA_RandomSensor
+from SCA_ISensor import *
+
+class SCA_RandomSensor(SCA_ISensor):
+ """
+ This sensor activates randomly.
+ """
+
+ def setSeed(seed):
+ """
+ Sets the seed of the random number generator.
+
+ If the seed is 0, the generator will produce the same value on every call.
+
+ @type seed: integer.
+ """
+ def getSeed():
+ """
+ Returns the initial seed of the generator. Equal seeds produce equal random
+ series.
+
+ @rtype: integer
+ """
+ def getLastDraw():
+ """
+ Returns the last random number generated.
+ """
diff --git a/source/gameengine/PyDoc/WhatsNew.py b/source/gameengine/PyDoc/WhatsNew.py
new file mode 100644
index 00000000000..64bef7ee1c8
--- /dev/null
+++ b/source/gameengine/PyDoc/WhatsNew.py
@@ -0,0 +1,34 @@
+# $Id$
+"""
+New Python Functionality in this Version of Blender
+===================================================
+
+This document lists what has been changed in the Game Engine Python API.
+
+Blender CVS
+ - Added L{KX_GameObject}.getDistanceTo() method. (thanks Charlie C)
+ - Added L{KX_PolygonMaterial} module
+
+Blender 2.36
+------------
+ - Added L{KX_CameraActuator} methods (thanks snail)
+
+Blender 2.35
+------------
+ - Added tic rate methods to L{GameLogic}
+ - Added stereo eye separation and focal length methods to L{Rasterizer}.
+ - Fixed L{Rasterizer}.makeScreenshot() method.
+ - Added setLogicTicRate() and setPhysicsTicRate() to L{GameLogic}
+
+Blender 2.34
+------------
+
+ - Added getType() and setType() to L{BL_ActionActuator} and L{KX_SoundActuator} (sgefant)
+ - New Scene module: L{KX_Scene}
+ - New Camera module: L{KX_Camera}
+ - New Light module: L{KX_Light}
+ - Added attributes to L{KX_GameObject}, L{KX_VertexProxy}
+ - L{KX_SCA_AddObjectActuator}.setObject(), L{KX_TrackToActuator}.setObject() and
+ L{KX_SceneActuator}.setCamera() now accept L{KX_GameObject}s as parameters
+
+"""
diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt
new file mode 100644
index 00000000000..9fe43a5bef7
--- /dev/null
+++ b/source/gameengine/Rasterizer/CMakeLists.txt
@@ -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) 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 *.cpp)
+
+SET(INC
+ .
+ ../../../source/kernel/gen_system
+ ../../../intern/string
+ ../../../intern/moto/include
+)
+
+BLENDERLIB(bf_rasterizer "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_rasterizer', sources, Split(incs), [], libtype=['game','player'], priority=[35,115], compileflags = cflags )
diff --git a/source/gameengine/Rasterizer/Makefile b/source/gameengine/Rasterizer/Makefile
new file mode 100644
index 00000000000..5f8eace8adb
--- /dev/null
+++ b/source/gameengine/Rasterizer/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 = rasterizer
+DIR = $(OCGDIR)/gameengine/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I../../kernel/gen_system
+ifeq ($(OS),darwin)
+ CPPFLAGS += -fpascal-strings
+endif
+###############
+
+SOURCEDIR = source/gameengine/Rasterizer
+DIRS = RAS_OpenGLRasterizer
+
+include nan_subdirs.mk
diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp
new file mode 100644
index 00000000000..999a79546a1
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp
@@ -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 *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+// don't show these anoying STL warnings
+#pragma warning (disable:4786)
+#endif
+
+#include "GEN_Map.h"
+#include "RAS_MaterialBucket.h"
+#include "STR_HashedString.h"
+#include "RAS_MeshObject.h"
+#define KX_NUM_MATERIALBUCKETS 100
+#include "RAS_IRasterizer.h"
+#include "RAS_IRenderTools.h"
+
+#include "RAS_BucketManager.h"
+
+#include <set>
+
+RAS_BucketManager::RAS_BucketManager()
+{
+
+}
+
+RAS_BucketManager::~RAS_BucketManager()
+{
+ RAS_BucketManagerClearAll();
+}
+
+/**
+ * struct alphamesh holds a mesh, (m_ms) it's depth, (m_z) and the bucket it came from (m_bucket.)
+ */
+struct RAS_BucketManager::alphamesh
+{
+public:
+ MT_Scalar m_z;
+ RAS_MaterialBucket::T_MeshSlotList::iterator m_ms;
+ RAS_MaterialBucket *m_bucket;
+ alphamesh(MT_Scalar z, RAS_MaterialBucket::T_MeshSlotList::iterator &ms, RAS_MaterialBucket *bucket) :
+ m_z(z),
+ m_ms(ms),
+ m_bucket(bucket)
+ {}
+};
+
+struct RAS_BucketManager::backtofront
+{
+ bool operator()(const alphamesh &a, const alphamesh &b)
+ {
+ return a.m_z < b.m_z;
+ }
+};
+
+
+void RAS_BucketManager::RenderAlphaBuckets(
+ const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools)
+{
+ BucketList::iterator bit;
+ std::multiset<alphamesh, backtofront> alphameshset;
+ RAS_MaterialBucket::T_MeshSlotList::iterator mit;
+
+ /* Camera's near plane equation: cam_norm.dot(point) + cam_origin */
+ const MT_Vector3 cam_norm(cameratrans.getBasis()[2]);
+ const MT_Scalar cam_origin = cameratrans.getOrigin()[2];
+ for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit)
+ {
+ (*bit)->ClearScheduledPolygons();
+ for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit)
+ {
+ if ((*mit).m_bVisible)
+ {
+ MT_Point3 pos((*mit).m_OpenGLMatrix[12], (*mit).m_OpenGLMatrix[13], (*mit).m_OpenGLMatrix[14]);
+ alphameshset.insert(alphamesh(MT_dot(cam_norm, pos) + cam_origin, mit, *bit));
+ }
+ }
+ }
+
+ // It shouldn't be strictly necessary to disable depth writes; but
+ // it is needed for compatibility.
+ rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_DISABLED);
+
+ int drawingmode;
+ std::multiset< alphamesh, backtofront>::iterator msit = alphameshset.begin();
+ for (; msit != alphameshset.end(); ++msit)
+ {
+ while ((*msit).m_bucket->ActivateMaterial(cameratrans, rasty, rendertools, drawingmode))
+ (*msit).m_bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *(*msit).m_ms, drawingmode);
+ }
+
+ rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
+}
+
+void RAS_BucketManager::Renderbuckets(
+ const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools)
+{
+ BucketList::iterator bucket;
+
+ rasty->EnableTextures(false);
+ rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
+
+ // beginning each frame, clear (texture/material) caching information
+ rasty->ClearCachingInfo();
+
+ RAS_MaterialBucket::StartFrame();
+ for (bucket = m_MaterialBuckets.begin(); bucket != m_MaterialBuckets.end(); ++bucket)
+ {
+ (*bucket)->ClearScheduledPolygons();
+ }
+
+ for (bucket = m_MaterialBuckets.begin(); bucket != m_MaterialBuckets.end(); ++bucket)
+ {
+ RAS_IPolyMaterial *tmp = (*bucket)->GetPolyMaterial();
+ if(tmp->IsZSort() || tmp->GetFlag() &RAS_FORCEALPHA )
+ rasty->SetAlphaTest(true);
+ else
+ rasty->SetAlphaTest(false);
+
+ (*bucket)->Render(cameratrans,rasty,rendertools);
+ }
+ rasty->SetAlphaTest(false);
+
+ RenderAlphaBuckets(cameratrans, rasty, rendertools);
+ RAS_MaterialBucket::EndFrame();
+}
+
+RAS_MaterialBucket* RAS_BucketManager::RAS_BucketManagerFindBucket(RAS_IPolyMaterial * material)
+{
+ BucketList::iterator it;
+ for (it = m_MaterialBuckets.begin(); it != m_MaterialBuckets.end(); it++)
+ {
+ if (*(*it)->GetPolyMaterial() == *material)
+ return *it;
+ }
+
+ for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++)
+ {
+ if (*(*it)->GetPolyMaterial() == *material)
+ return *it;
+ }
+
+ RAS_MaterialBucket *bucket = new RAS_MaterialBucket(material);
+ if (bucket->IsTransparant())
+ m_AlphaBuckets.push_back(bucket);
+ else
+ m_MaterialBuckets.push_back(bucket);
+
+ return bucket;
+}
+
+void RAS_BucketManager::RAS_BucketManagerClearAll()
+{
+ BucketList::iterator it;
+ for (it = m_MaterialBuckets.begin(); it != m_MaterialBuckets.end(); it++)
+ {
+ delete (*it);
+ }
+ for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++)
+ {
+ delete(*it);
+ }
+
+ m_MaterialBuckets.clear();
+ m_AlphaBuckets.clear();
+}
diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.h b/source/gameengine/Rasterizer/RAS_BucketManager.h
new file mode 100644
index 00000000000..59144f1e175
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_BucketManager.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 *****
+ */
+// this will be put in a class later on
+
+#ifndef __RAS_BUCKETMANAGER
+#define __RAS_BUCKETMANAGER
+
+#include "MT_Transform.h"
+#include "RAS_MaterialBucket.h"
+#include "GEN_Map.h"
+
+#include <vector>
+
+class RAS_BucketManager
+{
+ //GEN_Map<class RAS_IPolyMaterial,class RAS_MaterialBucket*> m_MaterialBuckets;
+
+ typedef std::vector<class RAS_MaterialBucket*> BucketList;
+ BucketList m_MaterialBuckets;
+ BucketList m_AlphaBuckets;
+
+ struct alphamesh;
+ struct backtofront;
+
+public:
+ RAS_BucketManager();
+ virtual ~RAS_BucketManager();
+
+ void RenderAlphaBuckets(const MT_Transform& cameratrans,
+ RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools);
+ void Renderbuckets(const MT_Transform & cameratrans,
+ RAS_IRasterizer* rasty,
+ class RAS_IRenderTools* rendertools);
+
+ RAS_MaterialBucket* RAS_BucketManagerFindBucket(RAS_IPolyMaterial * material);
+
+
+private:
+ void RAS_BucketManagerClearAll();
+
+};
+
+#endif //__RAS_BUCKETMANAGER
+
diff --git a/source/gameengine/Rasterizer/RAS_CameraData.h b/source/gameengine/Rasterizer/RAS_CameraData.h
new file mode 100644
index 00000000000..69a43dd64e9
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_CameraData.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef __RAS_CAMERADATA_H
+#define __RAS_CAMERADATA_H
+
+struct RAS_CameraData
+{
+ float m_lens;
+ float m_clipstart;
+ float m_clipend;
+ bool m_perspective;
+ bool m_viewport;
+ int m_viewportleft;
+ int m_viewportbottom;
+ int m_viewportright;
+ int m_viewporttop;
+
+ RAS_CameraData(float lens = 35., float clipstart = 0.1, float clipend = 100., bool perspective = true,
+ bool viewport = false, int viewportleft = 0, int viewportbottom = 0, int viewportright = 0, int viewporttop = 0) :
+ m_lens(lens),
+ m_clipstart(clipstart),
+ m_clipend(clipend),
+ m_perspective(perspective),
+ m_viewport(viewport),
+ m_viewportleft(viewportleft),
+ m_viewportbottom(viewportbottom),
+ m_viewportright(viewportright),
+ m_viewporttop(viewporttop)
+ {
+ }
+};
+
+#endif //__RAS_CAMERADATA_H
+
diff --git a/source/gameengine/Rasterizer/RAS_Deformer.h b/source/gameengine/Rasterizer/RAS_Deformer.h
new file mode 100644
index 00000000000..9aeb85c5740
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_Deformer.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 RAS_DEFORMER
+#define RAS_DEFORMER
+
+#ifdef WIN32
+#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
+#endif //WIN32
+
+#include "GEN_Map.h"
+
+class RAS_Deformer
+{
+public:
+ RAS_Deformer(){};
+ virtual ~RAS_Deformer(){};
+ virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map)=0;
+ virtual bool Apply(class RAS_IPolyMaterial *polymat)=0;
+ virtual void Update(void)=0;
+ virtual RAS_Deformer *GetReplica()=0;
+protected:
+ class RAS_MeshObject *m_pMesh;
+};
+
+#endif
+
diff --git a/source/gameengine/Rasterizer/RAS_FramingManager.cpp b/source/gameengine/Rasterizer/RAS_FramingManager.cpp
new file mode 100644
index 00000000000..131893bd79f
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_FramingManager.cpp
@@ -0,0 +1,234 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "RAS_FramingManager.h"
+#include "RAS_Rect.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+ void
+RAS_FramingManager::
+ComputeDefaultFrustum(
+ const float camnear,
+ const float camfar,
+ const float lens,
+ const float design_aspect_ratio,
+ RAS_FrameFrustum & frustum
+){
+
+ /*
+ * Magic Blender calculation.
+ * Blender does not give a Field of View as lens but a size
+ * at 16 units away from the lens.
+ */
+ float halfSize = 16.f * camnear / lens;
+ float sizeX;
+ float sizeY;
+
+ if (design_aspect_ratio > 1.f) {
+ // halfsize defines the width
+ sizeX = halfSize;
+ sizeY = halfSize/design_aspect_ratio;
+ } else {
+ // halfsize defines the height
+ sizeX = halfSize * design_aspect_ratio;
+ sizeY = halfSize;
+ }
+
+ frustum.x2 = sizeX;
+ frustum.x1 = -frustum.x2;
+ frustum.y2 = sizeY;
+ frustum.y1 = -frustum.y2;
+ frustum.camnear = camnear;
+ frustum.camfar = camfar;
+}
+
+ void
+RAS_FramingManager::
+ComputeBestFitViewRect(
+ const RAS_Rect &availableViewport,
+ const float design_aspect_ratio,
+ RAS_Rect &viewport
+){
+ // try and honour the aspect ratio when setting the
+ // drawable area. If we don't do this we are liable
+ // to get a lot of distortion in the rendered image.
+
+ int width = availableViewport.GetWidth();
+ int height = availableViewport.GetHeight();
+ float window_aspect = float(width)/float(height);
+
+ if (window_aspect < design_aspect_ratio) {
+ int v_height = (int)(width / design_aspect_ratio);
+ int left_over = (height - v_height) / 2;
+
+ viewport.SetLeft(availableViewport.GetLeft());
+ viewport.SetBottom(availableViewport.GetBottom() + left_over);
+ viewport.SetRight(availableViewport.GetLeft() + width);
+ viewport.SetTop(availableViewport.GetBottom() + left_over + v_height);
+
+ } else {
+ int v_width = (int)(height * design_aspect_ratio);
+ int left_over = (width - v_width) / 2;
+
+ viewport.SetLeft(availableViewport.GetLeft() + left_over);
+ viewport.SetBottom(availableViewport.GetBottom());
+ viewport.SetRight(availableViewport.GetLeft() + v_width + left_over);
+ viewport.SetTop(availableViewport.GetBottom() + height);
+ }
+}
+
+ void
+RAS_FramingManager::
+ComputeViewport(
+ const RAS_FrameSettings &settings,
+ const RAS_Rect &availableViewport,
+ RAS_Rect &viewport
+){
+
+ RAS_FrameSettings::RAS_FrameType type = settings.FrameType();
+ const int winx = availableViewport.GetWidth();
+ const int winy = availableViewport.GetHeight();
+
+ const float design_width = float(settings.DesignAspectWidth());
+ const float design_height = float(settings.DesignAspectHeight());
+
+ float design_aspect_ratio = float(1);
+
+ if (design_height == float(0)) {
+ // well this is ill defined
+ // lets just scale the thing
+
+ type = RAS_FrameSettings::e_frame_scale;
+ } else {
+ design_aspect_ratio = design_width/design_height;
+ }
+
+ switch (type) {
+
+ case RAS_FrameSettings::e_frame_scale :
+ case RAS_FrameSettings::e_frame_extend:
+ {
+ viewport.SetLeft(availableViewport.GetLeft());
+ viewport.SetBottom(availableViewport.GetBottom());
+ viewport.SetRight(availableViewport.GetLeft() + int(winx));
+ viewport.SetTop(availableViewport.GetBottom() + int(winy));
+
+ break;
+ }
+
+ case RAS_FrameSettings::e_frame_bars:
+ {
+ ComputeBestFitViewRect(
+ availableViewport,
+ design_aspect_ratio,
+ viewport
+ );
+
+ break;
+ }
+ default :
+ break;
+ }
+}
+
+ void
+RAS_FramingManager::
+ComputeFrustum(
+ const RAS_FrameSettings &settings,
+ const RAS_Rect &availableViewport,
+ const RAS_Rect &viewport,
+ const float lens,
+ const float camnear,
+ const float camfar,
+ RAS_FrameFrustum &frustum
+){
+
+ RAS_FrameSettings::RAS_FrameType type = settings.FrameType();
+
+ const float design_width = float(settings.DesignAspectWidth());
+ const float design_height = float(settings.DesignAspectHeight());
+
+ float design_aspect_ratio = float(1);
+
+ if (design_height == float(0)) {
+ // well this is ill defined
+ // lets just scale the thing
+
+ type = RAS_FrameSettings::e_frame_scale;
+ } else {
+ design_aspect_ratio = design_width/design_height;
+ }
+
+ ComputeDefaultFrustum(
+ camnear,
+ camfar,
+ lens,
+ design_aspect_ratio,
+ frustum
+ );
+
+ switch (type) {
+
+ case RAS_FrameSettings::e_frame_extend:
+ {
+ RAS_Rect vt;
+ ComputeBestFitViewRect(
+ availableViewport,
+ design_aspect_ratio,
+ vt
+ );
+
+ // now scale the calculated frustum by the difference
+ // between vt and the viewport in each axis.
+ // These are always > 1
+
+ float x_scale = float(viewport.GetWidth())/float(vt.GetWidth());
+ float y_scale = float(viewport.GetHeight())/float(vt.GetHeight());
+
+ frustum.x1 *= x_scale;
+ frustum.x2 *= x_scale;
+ frustum.y1 *= y_scale;
+ frustum.y2 *= y_scale;
+
+ break;
+ }
+ case RAS_FrameSettings::e_frame_scale :
+ case RAS_FrameSettings::e_frame_bars:
+ default :
+ break;
+ }
+}
+
+
+
diff --git a/source/gameengine/Rasterizer/RAS_FramingManager.h b/source/gameengine/Rasterizer/RAS_FramingManager.h
new file mode 100644
index 00000000000..8b3cc1b2f19
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_FramingManager.h
@@ -0,0 +1,256 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 RAS_FRAMINGMANAGER_H
+#define RAS_FRAMINGMANAGER_H
+
+class RAS_Rect;
+
+/**
+ * @section RAS_FrameSettings
+ * This is a value type describing the framing used
+ * by a particular scene in the game engine.
+ * Each KX_Scene contains a RAS_FrameSetting describing
+ * how the frustum and viewport are to be modified
+ * depending on the canvas size.
+ *
+ * e_frame_scale means that the viewport is set to the current
+ * canvas size. If the view frustum aspect ratio is different
+ * to the canvas aspect this will lead to stretching.
+ *
+ * e_frame_extend means that the best fit viewport will be
+ * computed based upon the design aspect ratio
+ * and the view frustum will be adjusted so that
+ * more of the scene is visible.
+ *
+ * e_frame_bars means that the best fit viewport will be
+ * be computed based upon the design aspect ratio.
+ */
+
+class RAS_FrameSettings
+{
+public :
+
+ /**
+ * enum defining the policy to use
+ * in each axis.
+ */
+ enum RAS_FrameType {
+ e_frame_scale,
+ e_frame_extend,
+ e_frame_bars
+ };
+
+ /**
+ * Contructor
+ */
+
+ RAS_FrameSettings(
+ RAS_FrameType frame_type,
+ float bar_r,
+ float bar_g,
+ float bar_b,
+ unsigned int design_aspect_width,
+ unsigned int design_aspect_height
+ ):
+ m_frame_type(frame_type),
+ m_bar_r(bar_r),
+ m_bar_g(bar_g),
+ m_bar_b(bar_b),
+ m_design_aspect_width(design_aspect_width),
+ m_design_aspect_height(design_aspect_height)
+ {
+ };
+
+ RAS_FrameSettings(
+ ):
+ m_frame_type(e_frame_scale),
+ m_bar_r(0),
+ m_bar_g(0),
+ m_bar_b(0),
+ m_design_aspect_width(1),
+ m_design_aspect_height(1)
+ {
+ };
+
+ /**
+ * Accessors
+ */
+
+ const
+ RAS_FrameType &
+ FrameType(
+ ) const {
+ return m_frame_type;
+ };
+
+ float
+ BarRed(
+ ) const {
+ return m_bar_r;
+ };
+
+ float
+ BarGreen(
+ ) const {
+ return m_bar_g;
+ };
+
+ float
+ BarBlue(
+ ) const {
+ return m_bar_b;
+ };
+
+ unsigned int
+ DesignAspectWidth(
+ ) const {
+ return m_design_aspect_width;
+ };
+
+ unsigned int
+ DesignAspectHeight(
+ ) const {
+ return m_design_aspect_height;
+ };
+
+private :
+
+ /**
+ * private to force use of public constructor
+ */
+
+ RAS_FrameSettings(
+ const RAS_FrameSettings &
+ );
+
+ RAS_FrameType m_frame_type;
+ float m_bar_r;
+ float m_bar_g;
+ float m_bar_b;
+ unsigned int m_design_aspect_width;
+ unsigned int m_design_aspect_height;
+};
+
+struct RAS_FrameFrustum
+{
+ float camnear,camfar;
+ float x1,y1;
+ float x2,y2;
+};
+
+
+/**
+ * @section RAS_FramingManager
+ * This class helps to compute a view frustum
+ * and a viewport rectangle given the
+ * above settings and a description of the
+ * current canvas dimensions.
+ *
+ * You do not have to instantiate this class
+ * directly, it only contains static helper functions
+ */
+
+class RAS_FramingManager
+{
+public :
+
+ /**
+ * Compute a viewport given
+ * a RAS_FrameSettings and a description of the
+ * canvas.
+ */
+
+ static
+ void
+ ComputeViewport(
+ const RAS_FrameSettings &settings,
+ const RAS_Rect &availableViewport,
+ RAS_Rect &viewport
+ );
+
+
+ /**
+ * compute a frustrum given a valid viewport,
+ * RAS_FrameSettings, canvas description
+ * and camera description
+ */
+
+ static
+ void
+ ComputeFrustum(
+ const RAS_FrameSettings &settings,
+ const RAS_Rect &availableViewport,
+ const RAS_Rect &viewport,
+ const float lens,
+ const float camnear,
+ const float camfar,
+ RAS_FrameFrustum &frustum
+ );
+
+
+private :
+
+ static
+ void
+ ComputeDefaultFrustum(
+ const float camnear,
+ const float camfar,
+ const float lens,
+ const float design_aspect_ratio,
+ RAS_FrameFrustum & frustum
+ );
+
+ static
+ void
+ ComputeBestFitViewRect(
+ const RAS_Rect &availableViewport,
+ const float design_aspect_ratio,
+ RAS_Rect &viewport
+ );
+
+
+
+ /**
+ * Private constructor - this class is not meant
+ * for instanciation.
+ */
+
+ RAS_FramingManager(
+ );
+
+ RAS_FramingManager(
+ const RAS_FramingManager &
+ );
+};
+
+#endif
+
diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.h b/source/gameengine/Rasterizer/RAS_ICanvas.h
new file mode 100644
index 00000000000..f1f2a8bcf62
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_ICanvas.h
@@ -0,0 +1,174 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __RAS_ICANVAS
+#define __RAS_ICANVAS
+
+/**
+ * 2D rendering device context. The connection from 3d rendercontext to 2d surface.
+ */
+
+class RAS_Rect;
+
+
+class RAS_ICanvas
+{
+public:
+ enum BufferType {
+ COLOR_BUFFER=1,
+ DEPTH_BUFFER=2
+ };
+
+ enum RAS_MouseState
+ {
+ MOUSE_INVISIBLE=1,
+ MOUSE_WAIT,
+ MOUSE_NORMAL
+ };
+
+ virtual
+ ~RAS_ICanvas(
+ ) {
+ };
+
+ virtual
+ void
+ Init(
+ ) = 0;
+
+ virtual
+ void
+ BeginFrame(
+ )=0;
+
+ virtual
+ void
+ EndFrame(
+ )=0;
+
+ /**
+ * Initializes the canvas for drawing. Drawing to the canvas is
+ * only allowed between BeginDraw() and EndDraw().
+ *
+ * @retval false Acquiring the canvas failed.
+ * @retval true Acquiring the canvas succeeded.
+ *
+ */
+
+ virtual
+ bool
+ BeginDraw(
+ )=0;
+
+ /**
+ * Unitializes the canvas for drawing.
+ */
+
+ virtual
+ void
+ EndDraw(
+ )=0;
+
+
+ /// probably needs some arguments for PS2 in future
+ virtual
+ void
+ SwapBuffers(
+ )=0;
+
+ virtual
+ void
+ ClearBuffer(
+ int type
+ )=0;
+
+ virtual
+ void
+ ClearColor(
+ float r,
+ float g,
+ float b,
+ float a
+ )=0;
+
+ virtual
+ int
+ GetWidth(
+ ) const = 0;
+
+ virtual
+ int
+ GetHeight(
+ ) const = 0;
+
+ virtual
+ const RAS_Rect &
+ GetDisplayArea(
+ ) const = 0;
+
+ virtual
+ RAS_Rect &
+ GetDisplayArea(
+ ) = 0;
+
+ /**
+ * Set the visible vieport
+ */
+
+ virtual
+ void
+ SetViewPort(
+ int x1, int y1,
+ int x2, int y2
+ ) = 0;
+
+ virtual
+ void
+ SetMouseState(
+ RAS_MouseState mousestate
+ )=0;
+
+ virtual
+ void
+ SetMousePosition(
+ int x,
+ int y
+ )=0;
+
+ virtual
+ void
+ MakeScreenShot(
+ const char* filename
+ )=0;
+};
+
+#endif //__RAS_ICANVAS
+
diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
new file mode 100644
index 00000000000..b5882bd48c4
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
@@ -0,0 +1,160 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "RAS_IPolygonMaterial.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+RAS_IPolyMaterial::RAS_IPolyMaterial(const STR_String& texname,
+ const STR_String& matname,
+ int tile,
+ int tilexrep,
+ int tileyrep,
+ int mode,
+ bool transparant,
+ bool zsort,
+ int lightlayer,
+ bool bIsTriangle,
+ void* clientobject=NULL) :
+
+ m_texturename(texname),
+ m_materialname(matname),
+ m_tile(tile),
+ m_tilexrep(tilexrep),
+ m_tileyrep(tileyrep),
+ m_drawingmode (mode),
+ m_transparant(transparant),
+ m_zsort(zsort),
+ m_lightlayer(lightlayer),
+ m_bIsTriangle(bIsTriangle),
+ m_polymatid(m_newpolymatid++),
+ m_flag(0),
+ m_enabled(0),
+ m_multimode(0)
+{
+ m_shininess = 35.0;
+ m_specular = MT_Vector3(0.5,0.5,0.5);
+ m_specularity = 1.0;
+ m_diffuse = MT_Vector3(0.5,0.5,0.5);
+}
+
+
+bool RAS_IPolyMaterial::Equals(const RAS_IPolyMaterial& lhs) const
+{
+ if(m_flag &RAS_BLENDERMAT)
+ {
+ return (
+ this->m_multimode == lhs.m_multimode &&
+ this->m_flag == lhs.m_flag &&
+ this->m_drawingmode == lhs.m_drawingmode &&
+ this->m_lightlayer == lhs.m_lightlayer &&
+ this->m_texturename.hash() == lhs.m_texturename.hash() &&
+ this->m_materialname.hash() == lhs.m_materialname.hash()
+ );
+ }
+ else
+ {
+ return (
+ this->m_tile == lhs.m_tile &&
+ this->m_tilexrep == lhs.m_tilexrep &&
+ this->m_tileyrep == lhs.m_tileyrep &&
+ this->m_transparant == lhs.m_transparant &&
+ this->m_zsort == lhs.m_zsort &&
+ this->m_drawingmode == lhs.m_drawingmode &&
+ this->m_bIsTriangle == lhs.m_bIsTriangle &&
+ this->m_lightlayer == lhs.m_lightlayer &&
+ this->m_texturename.hash() == lhs.m_texturename.hash() &&
+ this->m_materialname.hash() == lhs.m_materialname.hash()
+ );
+ }
+}
+
+bool RAS_IPolyMaterial::Less(const RAS_IPolyMaterial& rhs) const
+{
+ if (Equals(rhs))
+ return false;
+
+ return m_polymatid < rhs.m_polymatid;
+}
+
+int RAS_IPolyMaterial::GetLightLayer() const
+{
+ return m_lightlayer;
+}
+
+bool RAS_IPolyMaterial::IsTransparant() const
+{
+ return m_transparant;
+}
+
+bool RAS_IPolyMaterial::IsZSort() const
+{
+ return m_zsort;
+}
+
+bool RAS_IPolyMaterial::UsesTriangles() const
+{
+ return m_bIsTriangle;
+}
+
+unsigned int RAS_IPolyMaterial::hash() const
+{
+ return m_texturename.hash();
+}
+
+int RAS_IPolyMaterial::GetDrawingMode() const
+{
+ return m_drawingmode;
+}
+
+const STR_String& RAS_IPolyMaterial::GetMaterialName() const
+{
+ return m_materialname;
+}
+
+const STR_String& RAS_IPolyMaterial::GetTextureName() const
+{
+ return m_texturename;
+}
+
+const unsigned int RAS_IPolyMaterial::GetFlag() const
+{
+ return m_flag;
+}
+const unsigned int RAS_IPolyMaterial::GetEnabled() const
+{
+ return m_enabled;
+}
+
+
+unsigned int RAS_IPolyMaterial::m_newpolymatid = 0;
diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h
new file mode 100644
index 00000000000..c02ff7c3566
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.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 __RAS_IPOLYGONMATERIAL
+#define __RAS_IPOLYGONMATERIAL
+
+#include "STR_HashedString.h"
+
+/**
+ * Polygon Material on which the material buckets are sorted
+ *
+ */
+#include "MT_Vector3.h"
+#include "STR_HashedString.h"
+
+class RAS_IRasterizer;
+
+enum MaterialProps
+{
+ RAS_ZSORT =1,
+ RAS_TRANSPARENT =2,
+ RAS_TRIANGLE =4,
+ RAS_MULTITEX =8,
+ RAS_MULTILIGHT =16,
+ RAS_BLENDERMAT =32,
+ RAS_GLSHADER =64,
+ RAS_AUTOGEN =128,
+ RAS_NORMAL =256,
+ RAS_DEFMULTI =512,
+ RAS_FORCEALPHA =1024
+};
+
+/**
+ * Material properties.
+ */
+class RAS_IPolyMaterial
+{
+ //todo: remove these variables from this interface/protocol class
+protected:
+ STR_HashedString m_texturename;
+ STR_HashedString m_materialname; //also needed for touchsensor
+ int m_tile;
+ int m_tilexrep,m_tileyrep;
+ int m_drawingmode; // tface->mode
+ bool m_transparant;
+ bool m_zsort;
+ int m_lightlayer;
+ bool m_bIsTriangle;
+
+ unsigned int m_polymatid;
+ static unsigned int m_newpolymatid;
+
+ // will move...
+ unsigned int m_flag;//MaterialProps
+ unsigned int m_enabled;// enabled for this mat
+ int m_multimode; // sum of values
+public:
+
+ MT_Vector3 m_diffuse;
+ float m_shininess;
+ MT_Vector3 m_specular;
+ float m_specularity;
+
+ /** Used to store caching information for materials. */
+ typedef void* TCachingInfo;
+
+ // care! these are taken from blender polygonflags, see file DNA_mesh_types.h for #define TF_BILLBOARD etc.
+ enum MaterialFlags
+ {
+ BILLBOARD_SCREENALIGNED = 256,
+ BILLBOARD_AXISALIGNED = 4096,
+ SHADOW =8192
+ };
+
+ RAS_IPolyMaterial(const STR_String& texname,
+ const STR_String& matname,
+ int tile,
+ int tilexrep,
+ int tileyrep,
+ int mode,
+ bool transparant,
+ bool zsort,
+ int lightlayer,
+ bool bIsTriangle,
+ void* clientobject);
+ virtual ~RAS_IPolyMaterial() {};
+
+ /**
+ * Returns the caching information for this material,
+ * This can be used to speed up the rasterizing process.
+ * @return The caching information.
+ */
+ virtual TCachingInfo GetCachingInfo(void) const { return 0; }
+
+ /**
+ * Activates the material in the rasterizer.
+ * On entry, the cachingInfo contains info about the last activated material.
+ * On exit, the cachingInfo should contain updated info about this material.
+ * @param rasty The rasterizer in which the material should be active.
+ * @param cachingInfo The information about the material used to speed up rasterizing.
+ */
+ virtual bool Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const
+ {
+ return false;
+ }
+ virtual void ActivateMeshSlot(const class KX_MeshSlot & ms, RAS_IRasterizer* rasty) const {}
+
+ virtual bool Equals(const RAS_IPolyMaterial& lhs) const;
+ bool Less(const RAS_IPolyMaterial& rhs) const;
+ int GetLightLayer() const;
+ bool IsTransparant() const;
+ bool IsZSort() const;
+ bool UsesTriangles() const;
+ unsigned int hash() const;
+ int GetDrawingMode() const;
+ const STR_String& GetMaterialName() const;
+ const STR_String& GetTextureName() const;
+ const unsigned int GetFlag() const;
+ const unsigned int GetEnabled() const;
+
+ /*
+ * PreCalculate texture gen
+ */
+ virtual void OnConstruction(){}
+};
+
+inline bool operator ==( const RAS_IPolyMaterial & rhs,const RAS_IPolyMaterial & lhs)
+{
+ return ( rhs.Equals(lhs));
+}
+
+inline bool operator < ( const RAS_IPolyMaterial & lhs, const RAS_IPolyMaterial & rhs)
+{
+ return lhs.Less(rhs);
+}
+
+#endif //__RAS_IPOLYGONMATERIAL
+
diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h
new file mode 100644
index 00000000000..560c6741260
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h
@@ -0,0 +1,411 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __RAS_IRASTERIZER
+#define __RAS_IRASTERIZER
+
+#ifdef WIN32
+#pragma warning (disable:4786)
+#endif
+
+#include "MT_CmMatrix4x4.h"
+#include "MT_Matrix4x4.h"
+
+class RAS_ICanvas;
+class RAS_IPolyMaterial;
+#include "RAS_MaterialBucket.h"
+
+/**
+ * 3D rendering device context interface.
+ */
+class RAS_IRasterizer
+{
+public:
+
+ RAS_IRasterizer(RAS_ICanvas* canv){};
+ virtual ~RAS_IRasterizer(){};
+ /**
+ */
+ enum {
+ RAS_RENDER_3DPOLYGON_TEXT = 16384
+ };
+ /**
+ * Drawing types
+ */
+ enum DrawType {
+ KX_BOUNDINGBOX = 1,
+ KX_WIREFRAME,
+ KX_SOLID,
+ KX_SHADED,
+ KX_TEXTURED
+ };
+
+ /**
+ * Valid SetDepthMask parameters
+ */
+ enum DepthMask {
+ KX_DEPTHMASK_ENABLED =1,
+ KX_DEPTHMASK_DISABLED
+ };
+
+ /**
+ */
+ enum {
+ KX_TWOSIDE = 512,
+ KX_LINES = 32768
+ };
+
+ /**
+ * Stereo mode types
+ */
+ enum StereoMode {
+ RAS_STEREO_NOSTEREO = 1,
+ RAS_STEREO_QUADBUFFERED,
+ RAS_STEREO_ABOVEBELOW,
+ RAS_STEREO_INTERLACED,
+ RAS_STEREO_ANAGLYPH,
+ RAS_STEREO_SIDEBYSIDE,
+ RAS_STEREO_VINTERLACE,
+
+ RAS_STEREO_MAXSTEREO
+ };
+
+ /**
+ * Texture gen modes.
+ */
+ enum TexCoGen {
+ RAS_TEXCO_GEN, //< GPU will generate texture coordinates
+ RAS_TEXCO_ORCO, //< Vertex coordinates (object space)
+ RAS_TEXCO_GLOB, //< Vertex coordinates (world space)
+ RAS_TEXCO_UV1, //< UV coordinates
+ RAS_TEXCO_OBJECT, //< Use another object's position as coordinates
+ RAS_TEXCO_LAVECTOR, //< Light vector as coordinates
+ RAS_TEXCO_VIEW, //< View vector as coordinates
+ RAS_TEXCO_STICKY, //< Sticky coordinates
+ RAS_TEXCO_WINDOW, //< Window coordinates
+ RAS_TEXCO_NORM, //< Normal coordinates
+ RAS_TEXTANGENT, //<
+ RAS_TEXCO_UV2, //<
+ RAS_TEXCO_DISABLE //< Disable this texture unit (cached)
+ };
+
+ /**
+ * Render pass identifiers for stereo.
+ */
+ enum StereoEye {
+ RAS_STEREO_LEFTEYE = 1,
+ RAS_STEREO_RIGHTEYE
+ };
+
+ /**
+ * SetDepthMask enables or disables writing a fragment's depth value
+ * to the Z buffer.
+ */
+ virtual void SetDepthMask(DepthMask depthmask)=0;
+ /**
+ * SetMaterial sets the material settings for subsequent primitives
+ * to be rendered with.
+ * The material will be cached.
+ */
+ virtual bool SetMaterial(const RAS_IPolyMaterial& mat)=0;
+ /**
+ * Init initialises the renderer.
+ */
+ virtual bool Init()=0;
+ /**
+ * Exit cleans up the renderer.
+ */
+ virtual void Exit()=0;
+ /**
+ * BeginFrame is called at the start of each frame.
+ */
+ virtual bool BeginFrame(int drawingmode, double time)=0;
+ /**
+ * ClearDepthBuffer clears the depth buffer.
+ */
+ virtual void ClearDepthBuffer()=0;
+ /**
+ * ClearCachingInfo clears the currently cached material.
+ */
+ virtual void ClearCachingInfo(void)=0;
+ /**
+ * EndFrame is called at the end of each frame.
+ */
+ virtual void EndFrame()=0;
+ /**
+ * SetRenderArea sets the render area from the 2d canvas
+ */
+ virtual void SetRenderArea()=0;
+
+ // Stereo Functions
+ /**
+ * SetStereoMode will set the stereo mode
+ */
+ virtual void SetStereoMode(const StereoMode stereomode)=0;
+ /**
+ * Stereo can be used to query if the rasterizer is in stereo mode.
+ * @return true if stereo mode is enabled.
+ */
+ virtual bool Stereo()=0;
+ /**
+ * Sets which eye buffer subsequent primitives will be rendered to.
+ */
+ virtual void SetEye(const StereoEye eye)=0;
+ virtual StereoEye GetEye()=0;
+ /**
+ * Sets the distance between eyes for stereo mode.
+ */
+ virtual void SetEyeSeparation(const float eyeseparation)=0;
+ virtual float GetEyeSeparation() = 0;
+ /**
+ * Sets the focal length for stereo mode.
+ */
+ virtual void SetFocalLength(const float focallength)=0;
+ virtual float GetFocalLength() = 0;
+ /**
+ * SwapBuffers swaps the back buffer with the front buffer.
+ */
+ virtual void SwapBuffers()=0;
+
+ // Drawing Functions
+ /**
+ * IndexPrimitives: Renders primitives.
+ * @param vertexarrays is an array of vertex arrays
+ * @param indexarrays is an array of index arrays
+ * @param mode determines the type of primitive stored in the vertex/index arrays:
+ * 0 triangles
+ * 1 lines (default)
+ * 2 quads
+ * @param polymat (reserved)
+ * @param useObjectColor will render the object using @param rgbacolor instead of
+ * vertex colors.
+ */
+ virtual void IndexPrimitives( const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot)=0;
+ /**
+ * @copydoc IndexPrimitives
+ * IndexPrimitivesEx will renormalize faces if @param vertexarrays[i].getFlag() & TV_CALCFACENORMAL
+ */
+ virtual void IndexPrimitives_Ex( const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor)=0;
+ /**
+ * IndexPrimitives_3DText will render text into the polygons.
+ * The text to be rendered is from @param rendertools client object's text property.
+ */
+ virtual void IndexPrimitives_3DText( const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor)=0;
+
+ virtual void IndexPrimitivesMulti(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot)=0;
+
+ virtual void IndexPrimitivesMulti_Ex(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor)=0;
+
+
+ virtual void SetProjectionMatrix(MT_CmMatrix4x4 & mat)=0;
+ /* This one should become our final version, methinks. */
+ /**
+ * Set the projection matrix for the rasterizer. This projects
+ * from camera coordinates to window coordinates.
+ * @param mat The projection matrix.
+ */
+ virtual void SetProjectionMatrix(const MT_Matrix4x4 & mat)=0;
+ /**
+ * Sets the modelview matrix.
+ */
+ virtual void SetViewMatrix(const MT_Matrix4x4 & mat,
+ const MT_Vector3& campos,
+ const MT_Point3 &camLoc,
+ const MT_Quaternion &camOrientQuat)=0;
+ /**
+ */
+ virtual const MT_Point3& GetCameraPosition()=0;
+ /**
+ */
+ virtual void LoadViewMatrix()=0;
+ /**
+ */
+ virtual void SetFog(float start,
+ float dist,
+ float r,
+ float g,
+ float b)=0;
+
+ virtual void SetFogColor(float r,
+ float g,
+ float b)=0;
+
+ virtual void SetFogStart(float start)=0;
+ /**
+ */
+ virtual void SetFogEnd(float end)=0;
+ /**
+ */
+ virtual void DisplayFog()=0;
+ /**
+ */
+ virtual void DisableFog()=0;
+
+ virtual void SetBackColor(float red,
+ float green,
+ float blue,
+ float alpha)=0;
+
+ /**
+ * @param drawingmode = KX_BOUNDINGBOX, KX_WIREFRAME, KX_SOLID, KX_SHADED or KX_TEXTURED.
+ */
+ virtual void SetDrawingMode(int drawingmode)=0;
+ /**
+ * @return the current drawing mode: KX_BOUNDINGBOX, KX_WIREFRAME, KX_SOLID, KX_SHADED or KX_TEXTURED.
+ */
+ virtual int GetDrawingMode()=0;
+ /**
+ */
+ virtual void EnableTextures(bool enable)=0;
+ /**
+ * Sets face culling
+ */
+ virtual void SetCullFace(bool enable)=0;
+ /**
+ * Sets wireframe mode.
+ */
+ virtual void SetLines(bool enable)=0;
+ /**
+ */
+ virtual double GetTime()=0;
+ /**
+ * Generates a projection matrix from the specified frustum.
+ * @param left the left clipping plane
+ * @param right the right clipping plane
+ * @param bottom the bottom clipping plane
+ * @param top the top clipping plane
+ * @param frustnear the near clipping plane
+ * @param frustfar the far clipping plane
+ * @return a 4x4 matrix representing the projection transform.
+ */
+ virtual MT_Matrix4x4 GetFrustumMatrix(
+ float left,
+ float right,
+ float bottom,
+ float top,
+ float frustnear,
+ float frustfar,
+ bool perspective = true
+ )=0;
+ /**
+ * Sets the specular color component of the lighting equation.
+ */
+ virtual void SetSpecularity(float specX,
+ float specY,
+ float specZ,
+ float specval)=0;
+
+ /**
+ * Sets the specular exponent component of the lighting equation.
+ */
+ virtual void SetShinyness(float shiny)=0;
+ /**
+ * Sets the diffuse color component of the lighting equation.
+ */
+ virtual void SetDiffuse(float difX,
+ float difY,
+ float difZ,
+ float diffuse)=0;
+ /**
+ * Sets the emissive color component of the lighting equation.
+ */
+ virtual void SetEmissive(float eX,
+ float eY,
+ float eZ,
+ float e
+ )=0;
+
+ virtual void SetAmbientColor(float red, float green, float blue)=0;
+ virtual void SetAmbient(float factor)=0;
+ /**
+ * Sets alpha testing
+ */
+ virtual void SetAlphaTest(bool enable)=0;
+
+ /**
+ * Sets a polygon offset. z depth will be: z1 = mult*z0 + add
+ */
+ virtual void SetPolygonOffset(float mult, float add) = 0;
+
+ virtual void DrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color)=0;
+
+ virtual void SetTexCoords(TexCoGen coords, int unit) = 0;
+ virtual void SetAttrib(int type) = 0;
+ virtual void GetViewMatrix(MT_Matrix4x4 &mat) const = 0;
+
+ virtual bool QueryLists(){return false;}
+ virtual bool QueryArrays(){return false;}
+
+ virtual void EnableMotionBlur(float motionblurvalue)=0;
+ virtual void DisableMotionBlur()=0;
+
+ virtual float GetMotionBlurValue()=0;
+ virtual int GetMotionBlurState()=0;
+ virtual void SetMotionBlurState(int newstate)=0;
+};
+
+#endif //__RAS_IRASTERIZER
+
+
diff --git a/source/gameengine/Rasterizer/RAS_IRenderTools.cpp b/source/gameengine/Rasterizer/RAS_IRenderTools.cpp
new file mode 100644
index 00000000000..aa0053f3d1d
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_IRenderTools.cpp
@@ -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 *****
+ */
+
+#include "RAS_IRenderTools.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void RAS_IRenderTools::SetViewMat(const MT_Transform& trans)
+{
+ trans.getValue(m_viewmat);
+}
+
+
+
+void RAS_IRenderTools::SetClientObject(void* obj)
+{
+ if (m_clientobject != obj)
+ {
+ m_clientobject = obj;
+ m_modified = true;
+ }
+}
+
+
+
+void RAS_IRenderTools::SetAuxilaryClientInfo(void* inf)
+{
+ m_auxilaryClientInfo = inf;
+}
+
+
+
+void RAS_IRenderTools::AddLight(struct RAS_LightObject* lightobject)
+{
+ m_lights.push_back(lightobject);
+}
+
+
+
+void RAS_IRenderTools::RemoveLight(struct RAS_LightObject* lightobject)
+{
+ std::vector<struct RAS_LightObject*>::iterator lit =
+ std::find(m_lights.begin(),m_lights.end(),lightobject);
+
+ if (!(lit==m_lights.end()))
+ m_lights.erase(lit);
+
+}
diff --git a/source/gameengine/Rasterizer/RAS_IRenderTools.h b/source/gameengine/Rasterizer/RAS_IRenderTools.h
new file mode 100644
index 00000000000..114783b9a47
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_IRenderTools.h
@@ -0,0 +1,202 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __RAS_IRENDERTOOLS
+#define __RAS_IRENDERTOOLS
+
+#include "MT_Transform.h"
+#include "RAS_IRasterizer.h"
+
+#include <vector>
+#include <algorithm>
+
+class RAS_IPolyMaterial;
+struct RAS_LightObject;
+
+class RAS_IRenderTools
+{
+
+protected:
+ float m_viewmat[16];
+ void* m_clientobject;
+ void* m_auxilaryClientInfo;
+
+ bool m_modified;
+
+ std::vector<struct RAS_LightObject*> m_lights;
+
+
+public:
+ enum RAS_TEXT_RENDER_MODE {
+ RAS_TEXT_RENDER_NODEF = 0,
+ RAS_TEXT_NORMAL,
+ RAS_TEXT_PADDED,
+ RAS_TEXT_MAX
+ };
+
+ RAS_IRenderTools(
+ ) :
+ m_clientobject(NULL),
+ m_modified(true)
+ {
+ };
+
+ virtual
+ ~RAS_IRenderTools(
+ ) {};
+
+ virtual
+ void
+ BeginFrame(
+ RAS_IRasterizer* rasty
+ )=0;
+
+ virtual
+ void
+ EndFrame(
+ RAS_IRasterizer* rasty
+ )=0;
+
+ // the following function was formerly called 'Render'
+ // by it doesn't render anymore
+ // It only sets the transform for the rasterizer
+ // so must be renamed to 'applyTransform' or something
+
+ virtual
+ void
+ applyTransform(
+ class RAS_IRasterizer* rasty,
+ double* oglmatrix,
+ int drawingmode
+ )=0;
+
+ /**
+ * Renders 2D text string.
+ * @param mode The type of text
+ * @param text The string to render.
+ * @param xco Position on the screen (origin in lower left corner).
+ * @param yco Position on the screen (origin in lower left corner).
+ * @param width Width of the canvas to draw to.
+ * @param height Height of the canvas to draw to.
+ */
+ virtual
+ void
+ RenderText2D(
+ RAS_TEXT_RENDER_MODE mode,
+ const char* text,
+ int xco,
+ int yco,
+ int width,
+ int height
+ ) = 0;
+
+ // 3d text, mapped on polygon
+ virtual
+ void
+ RenderText(
+ int mode,
+ RAS_IPolyMaterial* polymat,
+ float v1[3],
+ float v2[3],
+ float v3[3],
+ float v4[3]
+ )=0;
+
+ virtual
+ void
+ SetViewMat(
+ const MT_Transform& trans
+ );
+
+ virtual
+ int
+ ProcessLighting(
+ int layer
+ )=0;
+
+ void
+ SetClientObject(
+ void* obj
+ );
+
+ void
+ SetAuxilaryClientInfo(
+ void* inf
+ );
+
+ virtual
+ void
+ PushMatrix(
+ )=0;
+
+ virtual
+ void
+ PopMatrix(
+ )=0;
+
+ virtual
+ void
+ AddLight(
+ struct RAS_LightObject* lightobject
+ );
+
+ virtual
+ void
+ RemoveLight(
+ struct RAS_LightObject* lightobject
+ );
+
+ virtual
+ void
+ MotionBlur(RAS_IRasterizer* rasterizer)=0;
+
+ virtual
+ class RAS_IPolyMaterial*
+ CreateBlenderPolyMaterial(
+ const STR_String &texname,
+ bool ba,
+ const STR_String& matname,
+ int tile,
+ int tilexrep,
+ int tileyrep,
+ int mode,
+ bool transparant,
+ bool zsort,
+ int lightlayer,
+ bool bIsTriangle,
+ void* clientobject,
+ void* tface
+ )=0;
+};
+
+#endif //__RAS_IRENDERTOOLS
+
+
diff --git a/source/gameengine/Rasterizer/RAS_LightObject.h b/source/gameengine/Rasterizer/RAS_LightObject.h
new file mode 100644
index 00000000000..2c22a588d76
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_LightObject.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 __RAS_LIGHTOBJECT_H
+#define __RAS_LIGHTOBJECT_H
+
+#include "MT_CmMatrix4x4.h"
+
+struct RAS_LightObject
+{
+ enum LightType{
+ LIGHT_SPOT,
+ LIGHT_SUN,
+ LIGHT_NORMAL
+ };
+ bool m_modified;
+ int m_layer;
+
+ float m_energy;
+ float m_distance;
+
+ float m_red;
+ float m_green;
+ float m_blue;
+
+ float m_att1;
+ float m_att2;
+ float m_spotsize;
+ float m_spotblend;
+
+ LightType m_type;
+ MT_CmMatrix4x4* m_worldmatrix;
+
+ bool m_nodiffuse;
+ bool m_nospecular;
+};
+
+#endif //__RAS_LIGHTOBJECT_H
+
diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp
new file mode 100644
index 00000000000..689772f51c4
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp
@@ -0,0 +1,332 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "RAS_MaterialBucket.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#pragma warning (disable:4786)
+#include <windows.h>
+#endif // WIN32
+
+#include "RAS_Polygon.h"
+#include "RAS_TexVert.h"
+#include "RAS_IRasterizer.h"
+#include "RAS_IRenderTools.h"
+#include "RAS_MeshObject.h"
+#include "RAS_Deformer.h" // __NLA
+
+
+
+KX_VertexIndex::KX_VertexIndex(int size)
+{
+ m_size = size;
+}
+
+
+
+void KX_VertexIndex::SetIndex(short loc,unsigned int index)
+{
+ m_indexarray[loc]=index;
+}
+
+bool KX_MeshSlot::Less(const KX_MeshSlot& lhs) const
+{
+ bool result = ((m_mesh < lhs.m_mesh ) ||
+ ((m_mesh == lhs.m_mesh)&&(m_OpenGLMatrix < lhs.m_OpenGLMatrix)));
+
+ return result;
+}
+
+
+
+RAS_MaterialBucket::RAS_MaterialBucket(RAS_IPolyMaterial* mat)
+ :m_bModified(true)
+{
+ m_bScheduled=true;
+ m_material = mat;
+}
+
+
+
+void RAS_MaterialBucket::SchedulePolygons(int drawingmode)
+{
+ m_bScheduled = true;
+}
+
+
+
+void RAS_MaterialBucket::ClearScheduledPolygons()
+{
+ m_bScheduled = false;
+}
+
+
+
+RAS_IPolyMaterial* RAS_MaterialBucket::GetPolyMaterial() const
+{
+ return m_material;
+}
+
+
+
+void RAS_MaterialBucket::SetMeshSlot(KX_MeshSlot& ms)
+{
+ m_meshSlots.insert(ms);
+}
+
+
+
+void RAS_MaterialBucket::RemoveMeshSlot(KX_MeshSlot& ms)
+{
+ T_MeshSlotList::iterator it = m_meshSlots.find(ms);
+
+ if (!(it == m_meshSlots.end()))
+ m_meshSlots.erase(it);
+
+}
+
+
+
+void RAS_MaterialBucket::MarkVisibleMeshSlot(KX_MeshSlot& ms,
+ bool visible,
+ bool color,
+ const MT_Vector4& rgbavec)
+{
+ T_MeshSlotList::iterator it = m_meshSlots.find(ms);
+
+ assert (!(it == m_meshSlots.end()));
+ (*it).m_bVisible = visible;
+ (*it).m_bObjectColor = color;
+ (*it).m_RGBAcolor= rgbavec;
+}
+
+bool RAS_MaterialBucket::IsTransparant() const
+{
+ return (m_material->IsTransparant());
+}
+
+
+
+void RAS_MaterialBucket::StartFrame()
+{
+}
+
+
+
+void RAS_MaterialBucket::EndFrame()
+{
+}
+
+unsigned int RAS_MaterialBucket::NumMeshSlots()
+{
+ return m_meshSlots.size();
+}
+
+RAS_MaterialBucket::T_MeshSlotList::iterator RAS_MaterialBucket::msBegin()
+{
+ return m_meshSlots.begin();
+}
+
+RAS_MaterialBucket::T_MeshSlotList::iterator RAS_MaterialBucket::msEnd()
+{
+ return m_meshSlots.end();
+}
+
+bool RAS_MaterialBucket::ActivateMaterial(const MT_Transform& cameratrans, RAS_IRasterizer* rasty,
+ RAS_IRenderTools *rendertools, int &drawmode)
+{
+ rendertools->SetViewMat(cameratrans);
+
+ if (!rasty->SetMaterial(*m_material))
+ return false;
+
+ bool dolights = false;
+ const unsigned int flag = m_material->GetFlag();
+
+
+ if( flag & RAS_BLENDERMAT)
+ dolights = (flag &RAS_MULTILIGHT)!=0;
+ else
+ dolights = (m_material->GetDrawingMode()&16)!=0;
+
+ if ((rasty->GetDrawingMode() < RAS_IRasterizer::KX_SOLID) || !dolights)
+ {
+ rendertools->ProcessLighting(-1);
+ }
+ else
+ {
+ rendertools->ProcessLighting(m_material->GetLightLayer());
+ }
+
+ drawmode = (rasty->GetDrawingMode() < RAS_IRasterizer::KX_SOLID ?
+ 1: (m_material->UsesTriangles() ? 0 : 2));
+
+ return true;
+}
+
+void RAS_MaterialBucket::RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRasterizer* rasty,
+ RAS_IRenderTools* rendertools, const KX_MeshSlot &ms, int drawmode)
+{
+ if (!ms.m_bVisible)
+ return;
+
+ rendertools->SetClientObject(ms.m_clientObj);
+ m_material->ActivateMeshSlot(ms, rasty);
+
+ /* __NLA Do the deformation */
+ if (ms.m_pDeformer)
+ {
+ ms.m_pDeformer->Apply(m_material);
+ // KX_ReInstanceShapeFromMesh(ms.m_mesh); // Recompute the physics mesh. (Can't call KX_* from RAS_)
+ }
+ /* End __NLA */
+
+ if (rasty->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID)
+ ms.m_mesh->SortPolygons(cameratrans*MT_Transform(ms.m_OpenGLMatrix));
+
+ rendertools->PushMatrix();
+ rendertools->applyTransform(rasty,ms.m_OpenGLMatrix,m_material->GetDrawingMode());
+
+ if(rasty->QueryLists())
+ {
+ if(ms.m_DisplayList)
+ ms.m_DisplayList->SetModified(ms.m_mesh->MeshModified());
+ }
+
+ // Use the text-specific IndexPrimitives for text faces
+ if (m_material->GetDrawingMode() & RAS_IRasterizer::RAS_RENDER_3DPOLYGON_TEXT)
+ {
+ rasty->IndexPrimitives_3DText(
+ ms.m_mesh->GetVertexCache(m_material),
+ ms.m_mesh->GetIndexCache(m_material),
+ drawmode,
+ m_material,
+ rendertools, // needed for textprinting on polys
+ ms.m_bObjectColor,
+ ms.m_RGBAcolor);
+
+ }
+
+ // for using glMultiTexCoord
+ else if(m_material->GetFlag() & RAS_MULTITEX )
+ {
+ rasty->IndexPrimitivesMulti(
+ ms.m_mesh->GetVertexCache(m_material),
+ ms.m_mesh->GetIndexCache(m_material),
+ drawmode,
+ m_material,
+ rendertools,
+ ms.m_bObjectColor,
+ ms.m_RGBAcolor,
+ &ms.m_DisplayList
+ );
+ }
+
+ // for using glMultiTexCoord on deformer
+ else if(m_material->GetFlag() & RAS_DEFMULTI )
+ {
+ rasty->IndexPrimitivesMulti_Ex(
+ ms.m_mesh->GetVertexCache(m_material),
+ ms.m_mesh->GetIndexCache(m_material),
+ drawmode,
+ m_material,
+ rendertools,
+ ms.m_bObjectColor,
+ ms.m_RGBAcolor
+ );
+ }
+
+ // Use the (slower) IndexPrimitives_Ex which can recalc face normals & such
+ // for deformed objects - eventually should be extended to recalc ALL normals
+ else if (ms.m_pDeformer){
+ rasty->IndexPrimitives_Ex(
+ ms.m_mesh->GetVertexCache(m_material),
+ ms.m_mesh->GetIndexCache(m_material),
+ drawmode,
+ m_material,
+ rendertools, // needed for textprinting on polys
+ ms.m_bObjectColor,
+ ms.m_RGBAcolor
+ );
+ }
+ // Use the normal IndexPrimitives
+ else
+ {
+ rasty->IndexPrimitives(
+ ms.m_mesh->GetVertexCache(m_material),
+ ms.m_mesh->GetIndexCache(m_material),
+ drawmode,
+ m_material,
+ rendertools, // needed for textprinting on polys
+ ms.m_bObjectColor,
+ ms.m_RGBAcolor,
+ &ms.m_DisplayList
+ );
+ }
+
+ if(rasty->QueryLists()) {
+ if(ms.m_DisplayList)
+ ms.m_mesh->SetMeshModified(false);
+ }
+
+ rendertools->PopMatrix();
+}
+
+void RAS_MaterialBucket::Render(const MT_Transform& cameratrans,
+ RAS_IRasterizer* rasty,
+ RAS_IRenderTools* rendertools)
+{
+ if (m_meshSlots.begin()== m_meshSlots.end())
+ return;
+
+ //rendertools->SetViewMat(cameratrans);
+
+ //rasty->SetMaterial(*m_material);
+
+ if (m_meshSlots.size() >0)
+ {
+ rendertools->SetClientObject((*m_meshSlots.begin()).m_clientObj);
+ }
+
+ int drawmode;
+ for (T_MeshSlotList::const_iterator it = m_meshSlots.begin();
+ ! (it == m_meshSlots.end()); ++it)
+ {
+ while (ActivateMaterial(cameratrans, rasty, rendertools, drawmode))
+ RenderMeshSlot(cameratrans, rasty, rendertools, *it, drawmode);
+ }
+}
+
+
diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.h b/source/gameengine/Rasterizer/RAS_MaterialBucket.h
new file mode 100644
index 00000000000..7d875242c2e
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.h
@@ -0,0 +1,169 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __RAS_MATERIALBUCKET
+#define __RAS_MATERIALBUCKET
+
+#include "RAS_TexVert.h"
+#include "GEN_Map.h"
+#include "STR_HashedString.h"
+
+#include "MT_Transform.h"
+#include "RAS_IPolygonMaterial.h"
+#include "RAS_Deformer.h" // __NLA
+#include <vector>
+#include <map>
+#include <set>
+using namespace std;
+
+typedef vector<unsigned short> KX_IndexArray;
+typedef vector<RAS_TexVert> KX_VertexArray;
+typedef vector< KX_VertexArray* > vecVertexArray;
+typedef vector< KX_IndexArray* > vecIndexArrays;
+
+/**
+ * KX_VertexIndex
+ */
+struct KX_VertexIndex {
+public:
+ KX_VertexIndex(int size);
+ void SetIndex(short loc,unsigned int index);
+
+ // The vertex array
+ short m_vtxarray;
+ // An index into the vertex array for up to 4 verticies
+ unsigned short m_indexarray[4];
+ short m_size;
+};
+
+/**
+ * KX_ListSlot.
+ */
+class KX_ListSlot
+{
+public:
+ KX_ListSlot(){}
+ virtual ~KX_ListSlot(){}
+
+ virtual void SetModified(bool mod)=0;
+};
+
+/**
+ * KX_MeshSlot.
+ */
+class KX_MeshSlot
+{
+public:
+ void* m_clientObj;
+ RAS_Deformer* m_pDeformer; // __NLA
+ double* m_OpenGLMatrix;
+ class RAS_MeshObject* m_mesh;
+ mutable bool m_bVisible; // for visibility
+ mutable bool m_bObjectColor;
+ mutable MT_Vector4 m_RGBAcolor;
+ mutable KX_ListSlot* m_DisplayList; // for lists
+ KX_MeshSlot() :
+ m_pDeformer(NULL),
+ m_bVisible(true),
+ m_DisplayList(0)
+ {
+ }
+ ~KX_MeshSlot(){}
+ bool Less(const KX_MeshSlot& lhs) const;
+};
+
+
+inline bool operator <( const KX_MeshSlot& rhs,const KX_MeshSlot& lhs)
+{
+ return ( rhs.Less(lhs));
+}
+
+/**
+ * Contains a list of meshs with the same material properties.
+ */
+class RAS_MaterialBucket
+{
+public:
+ typedef std::set<KX_MeshSlot> T_MeshSlotList;
+
+ RAS_MaterialBucket(RAS_IPolyMaterial* mat);
+ virtual ~RAS_MaterialBucket() {}
+
+ void Render(const MT_Transform& cameratrans,
+ class RAS_IRasterizer* rasty,
+ class RAS_IRenderTools* rendertools);
+
+ void SchedulePolygons(int drawingmode);
+ void ClearScheduledPolygons();
+
+ RAS_IPolyMaterial* GetPolyMaterial() const;
+ bool IsTransparant() const;
+
+ static void StartFrame();
+ static void EndFrame();
+
+ void SetMeshSlot(KX_MeshSlot& ms);
+ void RemoveMeshSlot(KX_MeshSlot& ms);
+ void MarkVisibleMeshSlot(KX_MeshSlot& ms,
+ bool visible,
+ bool color,
+ const MT_Vector4& rgbavec);
+
+ void RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRasterizer* rasty,
+ RAS_IRenderTools* rendertools, const KX_MeshSlot &ms, int drawmode);
+ bool ActivateMaterial(const MT_Transform& cameratrans, RAS_IRasterizer* rasty,
+ RAS_IRenderTools *rendertools, int &drawmode);
+
+ unsigned int NumMeshSlots();
+ T_MeshSlotList::iterator msBegin();
+ T_MeshSlotList::iterator msEnd();
+
+ struct less
+ {
+ bool operator()(const RAS_MaterialBucket* x, const RAS_MaterialBucket* y) const
+ {
+ return *x->GetPolyMaterial() < *y->GetPolyMaterial();
+ }
+ };
+
+ typedef set<RAS_MaterialBucket*, less> Set;
+private:
+
+ T_MeshSlotList m_meshSlots;
+ bool m_bScheduled;
+ bool m_bModified;
+ RAS_IPolyMaterial* m_material;
+ double* m_pOGLMatrix;
+
+};
+
+#endif //__KX_BUCKET
+
diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.cpp b/source/gameengine/Rasterizer/RAS_MeshObject.cpp
new file mode 100644
index 00000000000..4219b641b5c
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_MeshObject.cpp
@@ -0,0 +1,699 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "RAS_MeshObject.h"
+#include "RAS_IRasterizer.h"
+#include "MT_MinMax.h"
+#include "MT_Point3.h"
+
+
+STR_String RAS_MeshObject::s_emptyname = "";
+
+
+
+KX_ArrayOptimizer::~KX_ArrayOptimizer()
+{
+ for (vector<KX_VertexArray*>::iterator itv = m_VertexArrayCache1.begin();
+ !(itv == m_VertexArrayCache1.end());++itv)
+ {
+ delete (*itv);
+ }
+
+ for (vector<KX_IndexArray*>::iterator iti = m_IndexArrayCache1.begin();
+ !(iti == m_IndexArrayCache1.end());++iti)
+ {
+ delete (*iti);
+ }
+
+ m_TriangleArrayCount.clear();
+ m_VertexArrayCache1.clear();
+ m_IndexArrayCache1.clear();
+
+
+}
+
+
+
+RAS_MeshObject::RAS_MeshObject(int lightlayer)
+ : m_bModified(true),
+ m_lightlayer(lightlayer),
+ m_zsort(false),
+ m_MeshMod(true),
+ m_class(0)
+{
+}
+
+
+bool RAS_MeshObject::MeshModified()
+{
+ return m_MeshMod;
+}
+
+
+RAS_MeshObject::~RAS_MeshObject()
+{
+ for (vector<RAS_Polygon*>::iterator it=m_Polygons.begin();!(it==m_Polygons.end());it++)
+ {
+ delete (*it);
+ }
+
+ ClearArrayData();
+}
+
+
+
+unsigned int RAS_MeshObject::GetLightLayer()
+{
+ return m_lightlayer;
+}
+
+
+
+int RAS_MeshObject::NumMaterials()
+{
+ return m_materials.size();
+}
+
+const STR_String& RAS_MeshObject::GetMaterialName(unsigned int matid)
+{
+ RAS_MaterialBucket* bucket = GetMaterialBucket(matid);
+
+ return bucket?bucket->GetPolyMaterial()->GetMaterialName():s_emptyname;
+}
+
+RAS_MaterialBucket* RAS_MeshObject::GetMaterialBucket(unsigned int matid)
+{
+ if (m_materials.size() > 0 && (matid < m_materials.size()))
+ {
+ RAS_MaterialBucket::Set::const_iterator it = m_materials.begin();
+ while (matid--) ++it;
+ return *it;
+ }
+
+ return NULL;
+}
+
+
+
+int RAS_MeshObject::NumPolygons()
+{
+ return m_Polygons.size();
+}
+
+
+
+RAS_Polygon* RAS_MeshObject::GetPolygon(int num)
+{
+ return m_Polygons[num];
+}
+
+
+
+RAS_MaterialBucket::Set::iterator RAS_MeshObject::GetFirstMaterial()
+{
+ return m_materials.begin();
+}
+
+
+
+RAS_MaterialBucket::Set::iterator RAS_MeshObject::GetLastMaterial()
+{
+ return m_materials.end();
+}
+
+
+
+void RAS_MeshObject::SetName(STR_String name)
+{
+ m_name = name;
+}
+
+
+
+const STR_String& RAS_MeshObject::GetName()
+{
+ return m_name;
+}
+
+
+
+const STR_String& RAS_MeshObject::GetTextureName(unsigned int matid)
+{
+ RAS_MaterialBucket* bucket = GetMaterialBucket(matid);
+
+ return bucket?bucket->GetPolyMaterial()->GetTextureName():s_emptyname;
+}
+
+
+
+void RAS_MeshObject::AddPolygon(RAS_Polygon* poly)
+{
+ m_Polygons.push_back(poly);
+}
+
+
+
+void RAS_MeshObject::DebugColor(unsigned int abgr)
+{
+/*
+ int numpolys = NumPolygons();
+ for (int i=0;i<numpolys;i++)
+ {
+ RAS_Polygon* poly = m_polygons[i];
+ for (int v=0;v<poly->VertexCount();v++)
+ {
+ RAS_TexVert* vtx = poly->GetVertex(v);
+ vtx->setDebugRGBA(abgr);
+ }
+ }
+ */
+
+ m_debugcolor = abgr;
+}
+
+
+
+void RAS_MeshObject::SchedulePoly(const KX_VertexIndex& idx,
+ int numverts,
+ RAS_IPolyMaterial* mat)
+{
+ //int indexpos = m_IndexArrayCount[idx.m_vtxarray];
+ //m_IndexArrayCount[idx.m_vtxarray] = indexpos + 3;
+
+ KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);
+ ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[0]);
+ ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[1]);
+ ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[2]);
+ if (!mat->UsesTriangles()) //if (!m_bUseTriangles)
+ {
+ //m_IndexArrayCount[idx.m_vtxarray] = indexpos+4;
+ ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[3]);
+ }
+}
+
+
+
+void RAS_MeshObject::ScheduleWireframePoly(const KX_VertexIndex& idx,
+ int numverts,
+ int edgecode,
+ RAS_IPolyMaterial* mat)
+{
+ //int indexpos = m_IndexArrayCount[idx.m_vtxarray];
+ int edgetrace = 1<<(numverts-1);
+ bool drawedge = (edgecode & edgetrace)!=0;
+ edgetrace = 1;
+ int prevvert = idx.m_indexarray[numverts-1];
+ KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);
+
+ for (int v = 0; v < numverts; v++)
+ {
+ unsigned int curvert = idx.m_indexarray[v];
+ if (drawedge)
+ {
+ ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(prevvert);
+ ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(curvert);
+ }
+ prevvert = curvert;
+ drawedge = (edgecode & edgetrace)!=0;
+ edgetrace*=2;
+ }
+ //m_IndexArrayCount[idx.m_vtxarray] = indexpos;
+}
+
+int RAS_MeshObject::FindOrAddVertex(int vtxarray,
+ const MT_Point3& xyz,
+ const MT_Point2& uv,
+ const MT_Point2& uv2,
+ const MT_Vector4& tangent,
+ const unsigned int rgbacolor,
+ const MT_Vector3& normal,
+ RAS_IPolyMaterial* mat,
+ int orgindex)
+{
+ KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
+
+ int numverts = ao->m_VertexArrayCache1[vtxarray]->size();//m_VertexArrayCount[vtxarray];
+ RAS_TexVert newvert(xyz,uv,uv2,tangent,rgbacolor,normal, 0);
+#define KX_FIND_SHARED_VERTICES
+#ifdef KX_FIND_SHARED_VERTICES
+
+ for (std::vector<RAS_MatArrayIndex>::iterator it = m_xyz_index_to_vertex_index_mapping[orgindex].begin();
+ it != m_xyz_index_to_vertex_index_mapping[orgindex].end();
+ it++)
+ {
+ if ((*it).m_arrayindex1 == ao->m_index1 &&
+ (*it).m_array == vtxarray &&
+ *(*it).m_matid == *mat &&
+ (*ao->m_VertexArrayCache1[vtxarray])[(*it).m_index].closeTo(&newvert)
+ )
+ {
+ return (*it).m_index;
+ }
+ }
+#endif // KX_FIND_SHARED_VERTICES
+
+ // no vertex found, add one
+ ao->m_VertexArrayCache1[vtxarray]->push_back(newvert);
+ // printf("(%f,%f,%f) ",xyz[0],xyz[1],xyz[2]);
+ RAS_MatArrayIndex idx;
+ idx.m_arrayindex1 = ao->m_index1;
+ idx.m_array = vtxarray;
+ idx.m_index = numverts;
+ idx.m_matid = mat;
+ m_xyz_index_to_vertex_index_mapping[orgindex].push_back(idx);
+
+ return numverts;
+}
+
+
+
+const vecVertexArray& RAS_MeshObject::GetVertexCache (RAS_IPolyMaterial* mat)
+{
+ KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
+
+ return ao->m_VertexArrayCache1;
+}
+
+
+
+int RAS_MeshObject::GetVertexArrayLength(RAS_IPolyMaterial* mat)
+{
+ int len = 0;
+
+ const vecVertexArray & vertexvec = GetVertexCache(mat);
+ vector<KX_VertexArray*>::const_iterator it = vertexvec.begin();
+
+ for (; it != vertexvec.end(); ++it)
+ {
+ len += (*it)->size();
+ }
+
+ return len;
+}
+
+
+
+RAS_TexVert* RAS_MeshObject::GetVertex(unsigned int matid,
+ unsigned int index)
+{
+ RAS_TexVert* vertex = NULL;
+
+ RAS_MaterialBucket* bucket = GetMaterialBucket(matid);
+ if (bucket)
+ {
+ RAS_IPolyMaterial* mat = bucket->GetPolyMaterial();
+ if (mat)
+ {
+ const vecVertexArray & vertexvec = GetVertexCache(mat);
+ vector<KX_VertexArray*>::const_iterator it = vertexvec.begin();
+
+ for (unsigned int len = 0; it != vertexvec.end(); ++it)
+ {
+ if (index < len + (*it)->size())
+ {
+ vertex = &(*(*it))[index-len];
+ break;
+ }
+ else
+ {
+ len += (*it)->size();
+ }
+ }
+ }
+ }
+
+ return vertex;
+}
+
+
+
+const vecIndexArrays& RAS_MeshObject::GetIndexCache (RAS_IPolyMaterial* mat)
+{
+ KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
+
+ return ao->m_IndexArrayCache1;
+}
+
+
+
+KX_ArrayOptimizer* RAS_MeshObject::GetArrayOptimizer(RAS_IPolyMaterial* polymat)
+{
+ KX_ArrayOptimizer** aop = (m_matVertexArrayS[*polymat]);
+
+ if (aop)
+ return *aop;
+
+ int numelements = m_matVertexArrayS.size();
+ m_sortedMaterials.push_back(polymat);
+
+ KX_ArrayOptimizer* ao = new KX_ArrayOptimizer(numelements);
+ m_matVertexArrayS.insert(*polymat,ao);
+
+ return ao;
+}
+
+
+
+void RAS_MeshObject::Bucketize(double* oglmatrix,
+ void* clientobj,
+ bool useObjectColor,
+ const MT_Vector4& rgbavec)
+{
+ KX_MeshSlot ms;
+ ms.m_clientObj = clientobj;
+ ms.m_mesh = this;
+ ms.m_OpenGLMatrix = oglmatrix;
+ ms.m_bObjectColor = useObjectColor;
+ ms.m_RGBAcolor = rgbavec;
+
+ for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
+ {
+ RAS_MaterialBucket* bucket = *it;
+ bucket->SchedulePolygons(0);
+// KX_ArrayOptimizer* oa = GetArrayOptimizer(bucket->GetPolyMaterial());
+ bucket->SetMeshSlot(ms);
+ }
+
+}
+
+
+
+void RAS_MeshObject::MarkVisible(double* oglmatrix,
+ void* clientobj,
+ bool visible,
+ bool useObjectColor,
+ const MT_Vector4& rgbavec)
+{
+ KX_MeshSlot ms;
+ ms.m_clientObj = clientobj;
+ ms.m_mesh = this;
+ ms.m_OpenGLMatrix = oglmatrix;
+ ms.m_RGBAcolor = rgbavec;
+ ms.m_bObjectColor= useObjectColor;
+
+ for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
+ {
+ RAS_MaterialBucket* bucket = *it;
+ bucket->SchedulePolygons(0);
+// KX_ArrayOptimizer* oa = GetArrayOptimizer(bucket->GetPolyMaterial());
+ bucket->MarkVisibleMeshSlot(ms,visible,useObjectColor,rgbavec);
+ }
+}
+
+
+void RAS_MeshObject::RemoveFromBuckets(double* oglmatrix,
+ void* clientobj)
+{
+ KX_MeshSlot ms;
+ ms.m_clientObj = clientobj;
+ ms.m_mesh = this;
+ ms.m_OpenGLMatrix = oglmatrix;
+
+ for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
+ {
+ RAS_MaterialBucket* bucket = *it;
+// RAS_IPolyMaterial* polymat = bucket->GetPolyMaterial();
+ bucket->SchedulePolygons(0);
+ //KX_ArrayOptimizer* oa = GetArrayOptimizer(polymat);
+ bucket->RemoveMeshSlot(ms);
+ }
+
+}
+
+
+
+/*
+ * RAS_MeshObject::GetVertex returns the vertex located somewhere in the vertexpool
+ * it is the clients responsibility to make sure the array and index are valid
+ */
+RAS_TexVert* RAS_MeshObject::GetVertex(short array,
+ unsigned int index,
+ RAS_IPolyMaterial* polymat)
+{
+ KX_ArrayOptimizer* ao = GetArrayOptimizer(polymat);//*(m_matVertexArrays[*polymat]);
+ return &((*(ao->m_VertexArrayCache1)[array])[index]);
+}
+
+
+
+void RAS_MeshObject::ClearArrayData()
+{
+ for (int i=0;i<m_matVertexArrayS.size();i++)
+ {
+ KX_ArrayOptimizer** ao = m_matVertexArrayS.at(i);
+ if (ao)
+ delete *ao;
+ }
+}
+
+
+
+/**
+ * RAS_MeshObject::CreateNewVertices creates vertices within sorted pools of vertices that share same material
+*/
+int RAS_MeshObject::FindVertexArray(int numverts,
+ RAS_IPolyMaterial* polymat)
+{
+// bool found=false;
+ int array=-1;
+
+ KX_ArrayOptimizer* ao = GetArrayOptimizer(polymat);
+
+ for (unsigned int i=0;i<ao->m_VertexArrayCache1.size();i++)
+ {
+ if ( (ao->m_TriangleArrayCount[i] + (numverts-2)) < BUCKET_MAX_TRIANGLES)
+ {
+ if((ao->m_VertexArrayCache1[i]->size()+numverts < BUCKET_MAX_INDICES))
+ {
+ array = i;
+ ao->m_TriangleArrayCount[array]+=numverts-2;
+ break;
+ }
+ }
+ }
+
+ if (array == -1)
+ {
+ array = ao->m_VertexArrayCache1.size();
+ vector<RAS_TexVert>* va = new vector<RAS_TexVert>;
+ ao->m_VertexArrayCache1.push_back(va);
+ KX_IndexArray *ia = new KX_IndexArray();
+ ao->m_IndexArrayCache1.push_back(ia);
+ ao->m_TriangleArrayCount.push_back(numverts-2);
+ }
+
+ return array;
+}
+
+
+
+
+//void RAS_MeshObject::Transform(const MT_Transform& trans)
+//{
+ //m_trans.translate(MT_Vector3(0,0,1));//.operator *=(trans);
+
+// for (int i=0;i<m_Polygons.size();i++)
+// {
+// m_Polygons[i]->Transform(trans);
+// }
+//}
+
+
+/*
+void RAS_MeshObject::RelativeTransform(const MT_Vector3& vec)
+{
+ for (int i=0;i<m_Polygons.size();i++)
+ {
+ m_Polygons[i]->RelativeTransform(vec);
+ }
+}
+*/
+
+
+
+void RAS_MeshObject::UpdateMaterialList()
+{
+ m_materials.clear();
+ unsigned int numpolys = m_Polygons.size();
+ // for all polygons, find out which material they use, and add it to the set of materials
+ for (unsigned int i=0;i<numpolys;i++)
+ {
+ m_materials.insert(m_Polygons[i]->GetMaterial());
+ }
+}
+
+struct RAS_MeshObject::polygonSlot
+{
+ float m_z;
+ RAS_Polygon *m_poly;
+
+ polygonSlot(float z, RAS_Polygon* poly) :
+ m_z(z),
+ m_poly(poly)
+ {}
+ /**
+ * pnorm and pval form the plane equation that the distance from is used to
+ * sort against.
+ */
+ polygonSlot(const MT_Vector3 &pnorm, const MT_Scalar &pval, RAS_MeshObject *mesh, RAS_Polygon* poly) :
+ m_poly(poly)
+ {
+ const KX_VertexIndex &base = m_poly->GetIndexBase();
+ RAS_TexVert *vert = mesh->GetVertex(base.m_vtxarray, base.m_indexarray[0], poly->GetMaterial()->GetPolyMaterial());
+ m_z = MT_dot(pnorm, vert->getLocalXYZ()) + pval;
+
+ for(int i = 1; i < m_poly->VertexCount(); i++)
+ {
+ vert = mesh->GetVertex(base.m_vtxarray, base.m_indexarray[i], poly->GetMaterial()->GetPolyMaterial());
+ float z = MT_dot(pnorm, vert->getLocalXYZ()) + pval;
+ m_z += z;
+ }
+ m_z /= m_poly->VertexCount();
+ }
+};
+
+struct RAS_MeshObject::backtofront
+{
+ bool operator()(const polygonSlot &a, const polygonSlot &b) const
+ {
+ return a.m_z < b.m_z;
+ }
+};
+
+struct RAS_MeshObject::fronttoback
+{
+ bool operator()(const polygonSlot &a, const polygonSlot &b) const
+ {
+ return a.m_z > b.m_z;
+ }
+};
+
+
+void RAS_MeshObject::SortPolygons(const MT_Transform &transform)
+{
+ if (!m_zsort)
+ return;
+
+ // Extract camera Z plane...
+ const MT_Vector3 pnorm(transform.getBasis()[2]);
+ const MT_Scalar pval = transform.getOrigin()[2];
+
+ unsigned int numpolys = m_Polygons.size();
+ std::multiset<polygonSlot, backtofront> alphapolyset;
+ std::multiset<polygonSlot, fronttoback> solidpolyset;
+
+ for (unsigned int p = 0; p < numpolys; p++)
+ {
+ RAS_Polygon* poly = m_Polygons[p];
+ if (poly->IsVisible())
+ {
+ if (poly->GetMaterial()->GetPolyMaterial()->IsTransparant())
+ {
+ alphapolyset.insert(polygonSlot(pnorm, pval, this, poly));
+ } else {
+ solidpolyset.insert(polygonSlot(pnorm, pval, this, poly));
+ }
+ }
+ }
+
+ // Clear current array data.
+ for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
+ {
+ vector<KX_IndexArray*> *indexcache = &GetArrayOptimizer((*it)->GetPolyMaterial())->m_IndexArrayCache1;
+ for (vector<KX_IndexArray*>::iterator iit = indexcache->begin(); iit != indexcache->end(); ++iit)
+ (*iit)->clear();
+ }
+
+ std::multiset<polygonSlot, fronttoback>::iterator sit = solidpolyset.begin();
+ for (; sit != solidpolyset.end(); ++sit)
+ SchedulePoly((*sit).m_poly->GetVertexIndexBase(), (*sit).m_poly->VertexCount(), (*sit).m_poly->GetMaterial()->GetPolyMaterial());
+
+ std::multiset<polygonSlot, backtofront>::iterator ait = alphapolyset.begin();
+ for (; ait != alphapolyset.end(); ++ait)
+ SchedulePoly((*ait).m_poly->GetVertexIndexBase(), (*ait).m_poly->VertexCount(), (*ait).m_poly->GetMaterial()->GetPolyMaterial());
+}
+
+
+void RAS_MeshObject::SchedulePolygons(const MT_Transform &transform, int drawingmode)
+{
+// int nummaterials = m_materials.size();
+ int i;
+
+ if (m_bModified)
+ {
+ for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
+ {
+ RAS_MaterialBucket* bucket = *it;
+
+ bucket->SchedulePolygons(drawingmode);
+ if (bucket->GetPolyMaterial()->IsZSort())
+ m_zsort = true;
+ }
+
+ int numpolys = m_Polygons.size();
+
+ if ((drawingmode > RAS_IRasterizer::KX_BOUNDINGBOX) &&
+ (drawingmode < RAS_IRasterizer::KX_SOLID))
+ {
+ for (i=0;i<numpolys;i++)
+ {
+ RAS_Polygon* poly = m_Polygons[i];
+ if (poly->IsVisible())
+ ScheduleWireframePoly(poly->GetVertexIndexBase(),poly->VertexCount(),poly->GetEdgeCode()
+ ,poly->GetMaterial()->GetPolyMaterial());
+
+ }
+ m_zsort = false;
+ }
+ else
+ {
+ if (!m_zsort)
+ {
+ for (i=0;i<numpolys;i++)
+ {
+ RAS_Polygon* poly = m_Polygons[i];
+ if (poly->IsVisible())
+ {
+ SchedulePoly(poly->GetVertexIndexBase(),poly->VertexCount(),poly->GetMaterial()->GetPolyMaterial());
+ }
+ }
+ }
+ }
+
+ m_bModified = false;
+
+ m_MeshMod = true;
+ }
+}
diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.h b/source/gameengine/Rasterizer/RAS_MeshObject.h
new file mode 100644
index 00000000000..bf7d47061ef
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_MeshObject.h
@@ -0,0 +1,267 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __RAS_MESHOBJECT
+#define __RAS_MESHOBJECT
+
+#ifdef WIN32
+// disable the STL warnings ("debug information length > 255")
+#pragma warning (disable:4786)
+#endif
+
+#include <vector>
+#include <set>
+
+#include "RAS_Polygon.h"
+#include "RAS_MaterialBucket.h"
+#include "MT_Transform.h"
+
+#include "GEN_HashedPtr.h"
+
+/**
+ * This class holds an array of vertices and indicies.
+ */
+class KX_ArrayOptimizer
+{
+public:
+ KX_ArrayOptimizer(int index)
+ : m_index1(index)
+ {};
+ virtual ~KX_ArrayOptimizer();
+
+ vector<KX_VertexArray*> m_VertexArrayCache1;
+ vector<int> m_TriangleArrayCount;
+ vector<KX_IndexArray*> m_IndexArrayCache1;
+
+ /**
+ order in which they are stored into the mesh
+ */
+ int m_index1;
+};
+
+/**
+ * This struct holds a triangle.
+ */
+struct RAS_TriangleIndex
+{
+public:
+ int m_index[3];
+ int m_array;
+ RAS_IPolyMaterial* m_matid;
+ bool m_collider;
+};
+
+/**
+ * This class looks horribly broken. Only m_matid is used, and
+ * m_matid is a (int) RAS_IPolyMaterial*.
+ * --> m_matid == lhs.m_matid should be *m_matid == *lhs.m_matid
+ */
+class RAS_MatArrayIndex
+{
+public:
+
+ int m_arrayindex1;
+ RAS_IPolyMaterial* m_matid;
+ int m_array;
+ int m_index;
+
+/*
+ inline bool Less(const RAS_MatArrayIndex& lhs) const {
+ bool result =
+ ( (m_matid < lhs.m_matid) ||
+ ((m_matid == lhs.m_matid)&&(m_array < lhs.m_array)) ||
+ ((m_matid == lhs.m_matid) && (m_array == lhs.m_array) &&
+ (m_index < lhs.m_index))
+
+ );
+ return result;
+
+ }
+*/
+
+};
+/*
+inline bool operator <( const RAS_MatArrayIndex& rhs,const RAS_MatArrayIndex& lhs)
+{
+ return ( rhs.Less(lhs));
+}*/
+
+/**
+ * RAS_MeshObject stores mesh data for the renderer.
+ */
+class RAS_MeshObject
+{
+
+ // GEN_Map<class RAS_IPolyMaterial,KX_ArrayOptimizer*> m_matVertexArrayS;
+ //vector<class RAS_IPolyMaterial*,KX_ArrayOptimizer> m_vertexArrays;
+ virtual KX_ArrayOptimizer* GetArrayOptimizer(RAS_IPolyMaterial* polymat);
+ //vector<RAS_Polygon*> m_polygons;
+
+ unsigned int m_debugcolor;
+ bool m_bModified;
+ int m_lightlayer;
+
+ vector<class RAS_Polygon*> m_Polygons;
+ STR_String m_name;
+ static STR_String s_emptyname;
+ bool m_zsort;
+ bool m_MeshMod;
+
+ struct polygonSlot;
+ struct backtofront;
+ struct fronttoback;
+
+
+protected:
+ enum { BUCKET_MAX_INDICES = 65535 };//2048};//8192};
+ enum { BUCKET_MAX_TRIANGLES = 65535 };
+
+ GEN_Map<class RAS_IPolyMaterial,KX_ArrayOptimizer*> m_matVertexArrayS;
+
+ RAS_MaterialBucket::Set m_materials;
+public:
+ // for now, meshes need to be in a certain layer (to avoid sorting on lights in realtime)
+ RAS_MeshObject(int lightlayer);
+ virtual ~RAS_MeshObject();
+
+ vector<RAS_IPolyMaterial*> m_sortedMaterials;
+ vector<vector<RAS_MatArrayIndex> > m_xyz_index_to_vertex_index_mapping;
+ vector<RAS_TriangleIndex > m_triangle_indices;
+
+ int m_class;
+
+ unsigned int GetLightLayer();
+ int NumMaterials();
+ const STR_String& GetMaterialName(unsigned int matid);
+ RAS_MaterialBucket* GetMaterialBucket(unsigned int matid);
+ const STR_String& GetTextureName(unsigned int matid);
+ virtual void AddPolygon(RAS_Polygon* poly);
+ void UpdateMaterialList();
+
+ int NumPolygons();
+ RAS_Polygon* GetPolygon(int num);
+
+ virtual void Bucketize(
+ double* oglmatrix,
+ void* clientobj,
+ bool useObjectColor,
+ const MT_Vector4& rgbavec
+ );
+
+ void RemoveFromBuckets(
+ double* oglmatrix,
+ void* clientobj
+ );
+
+ void MarkVisible(
+ double* oglmatrix,
+ void* clientobj,
+ bool visible,
+ bool useObjectColor,
+ const MT_Vector4& rgbavec
+ );
+
+ void DebugColor(unsigned int abgr);
+
+ /**
+ * Sorts the polygons by their transformed z values.
+ */
+ void SortPolygons(const MT_Transform &transform);
+
+ void SchedulePolygons(
+ const MT_Transform &transform,
+ int drawingmode
+ );
+
+ void ClearArrayData();
+
+ RAS_MaterialBucket::Set::iterator GetFirstMaterial();
+ RAS_MaterialBucket::Set::iterator GetLastMaterial();
+
+ virtual RAS_TexVert* GetVertex(
+ short array,
+ unsigned int index,
+ RAS_IPolyMaterial* polymat
+ );
+
+ virtual int FindVertexArray(
+ int numverts,
+ RAS_IPolyMaterial* polymat
+ );
+
+ void SchedulePoly(
+ const KX_VertexIndex& idx,
+ int numverts,
+ RAS_IPolyMaterial* mat
+ );
+
+ void ScheduleWireframePoly(
+ const KX_VertexIndex& idx,
+ int numverts,
+ int edgecode,
+ RAS_IPolyMaterial* mat
+ );
+
+ // find (and share) or add vertices
+ // for some speedup, only the last 20 added vertices are searched for equality
+
+ virtual int FindOrAddVertex(
+ int vtxarray,
+ const MT_Point3& xyz,
+ const MT_Point2& uv,
+ const MT_Point2& uv2,
+ const MT_Vector4& tangent,
+ const unsigned int rgbacolor,
+ const MT_Vector3& normal,
+ RAS_IPolyMaterial* mat,
+ int orgindex
+ );
+
+ const vecVertexArray& GetVertexCache (RAS_IPolyMaterial* mat);
+
+ int GetVertexArrayLength(RAS_IPolyMaterial* mat);
+
+ RAS_TexVert* GetVertex(
+ unsigned int matid,
+ unsigned int index
+ );
+
+ const vecIndexArrays& GetIndexCache (RAS_IPolyMaterial* mat);
+ void SetName(STR_String name);
+ const STR_String& GetName();
+
+ bool MeshModified();
+ void SetMeshModified(bool v){m_MeshMod = v;}
+
+};
+
+#endif //__RAS_MESHOBJECT
+
diff --git a/source/gameengine/Rasterizer/RAS_ObjectColor.h b/source/gameengine/Rasterizer/RAS_ObjectColor.h
new file mode 100644
index 00000000000..1592fc57e77
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_ObjectColor.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 *****
+ */
+#ifndef __RAS_OBJECTCOLOR_H
+#define __RAS_OBJECTCOLOR_H
+
+struct RAS_ObjectColor {
+ float m_red;
+ float m_green;
+ float m_blue;
+};
+
+#endif //__RAS_OBJECTCOLOR_H
+
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/ARB_multitexture.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/ARB_multitexture.h
new file mode 100644
index 00000000000..a2f27ce3361
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/ARB_multitexture.h
@@ -0,0 +1,150 @@
+#ifndef __ARB_MULTITEXTURE_H__
+#define __ARB_MULTITEXTURE_H__
+
+/*
+*/
+
+/* ----------------------------------------------------------------------------
+ GL_ARB_multitexture
+---------------------------------------------------------------------------- */
+#ifdef GL_ARB_multitexture
+ #define GL_TEXTURE0_ARB 0x84C0
+ #define GL_TEXTURE1_ARB 0x84C1
+ #define GL_TEXTURE2_ARB 0x84C2
+ #define GL_TEXTURE3_ARB 0x84C3
+ #define GL_TEXTURE4_ARB 0x84C4
+ #define GL_TEXTURE5_ARB 0x84C5
+ #define GL_TEXTURE6_ARB 0x84C6
+ #define GL_TEXTURE7_ARB 0x84C7
+ #define GL_TEXTURE8_ARB 0x84C8
+ #define GL_TEXTURE9_ARB 0x84C9
+ #define GL_TEXTURE10_ARB 0x84CA
+ #define GL_ACTIVE_TEXTURE_ARB 0x84E0
+ #define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1
+ #define GL_MAX_TEXTURE_UNITS_ARB 0x84E2
+#endif
+
+
+/* ----------------------------------------------------------------------------
+ GL_ARB_texture_env_combine
+---------------------------------------------------------------------------- */
+#ifdef GL_ARB_texture_env_combine
+ #define GL_COMBINE_ARB 0x8570
+ #define GL_COMBINE_RGB_ARB 0x8571
+ #define GL_COMBINE_ALPHA_ARB 0x8572
+ #define GL_SOURCE0_RGB_ARB 0x8580
+ #define GL_SOURCE1_RGB_ARB 0x8581
+ #define GL_SOURCE2_RGB_ARB 0x8582
+ #define GL_SOURCE0_ALPHA_ARB 0x8588
+ #define GL_SOURCE1_ALPHA_ARB 0x8589
+ #define GL_SOURCE2_ALPHA_ARB 0x858A
+ #define GL_OPERAND0_RGB_ARB 0x8590
+ #define GL_OPERAND1_RGB_ARB 0x8591
+ #define GL_OPERAND2_RGB_ARB 0x8592
+ #define GL_OPERAND0_ALPHA_ARB 0x8598
+ #define GL_OPERAND1_ALPHA_ARB 0x8599
+ #define GL_OPERAND2_ALPHA_ARB 0x859A
+ #define GL_RGB_SCALE_ARB 0x8573
+ #define GL_ADD_SIGNED_ARB 0x8574
+ #define GL_INTERPOLATE_ARB 0x8575
+ #define GL_SUBTRACT_ARB 0x84E7
+ #define GL_CONSTANT_ARB 0x8576
+ #define GL_PRIMARY_COLOR_ARB 0x8577
+ #define GL_PREVIOUS_ARB 0x8578
+#endif
+
+/* ----------------------------------------------------------------------------
+ GL_ARB_texture_cube_map
+---------------------------------------------------------------------------- */
+#ifdef GL_ARB_texture_cube_map
+ #define GL_NORMAL_MAP_ARB 0x8511
+ #define GL_REFLECTION_MAP_ARB 0x8512
+ #define GL_TEXTURE_CUBE_MAP_ARB 0x8513
+ #define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514
+ #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515
+ #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516
+ #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517
+ #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518
+ #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519
+ #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A
+ #define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B
+ #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C
+#endif
+
+/* ----------------------------------------------------------------------------
+ GL_ARB_shader_objects
+---------------------------------------------------------------------------- */
+#ifdef GL_ARB_shader_objects
+ #define GL_PROGRAM_OBJECT_ARB 0x8B40
+ #define GL_SHADER_OBJECT_ARB 0x8B48
+ #define GL_OBJECT_TYPE_ARB 0x8B4E
+ #define GL_OBJECT_SUBTYPE_ARB 0x8B4F
+ #define GL_FLOAT_VEC2_ARB 0x8B50
+ #define GL_FLOAT_VEC3_ARB 0x8B51
+ #define GL_FLOAT_VEC4_ARB 0x8B52
+ #define GL_INT_VEC2_ARB 0x8B53
+ #define GL_INT_VEC3_ARB 0x8B54
+ #define GL_INT_VEC4_ARB 0x8B55
+ #define GL_BOOL_ARB 0x8B56
+ #define GL_BOOL_VEC2_ARB 0x8B57
+ #define GL_BOOL_VEC3_ARB 0x8B58
+ #define GL_BOOL_VEC4_ARB 0x8B59
+ #define GL_FLOAT_MAT2_ARB 0x8B5A
+ #define GL_FLOAT_MAT3_ARB 0x8B5B
+ #define GL_FLOAT_MAT4_ARB 0x8B5C
+ #define GL_SAMPLER_1D_ARB 0x8B5D
+ #define GL_SAMPLER_2D_ARB 0x8B5E
+ #define GL_SAMPLER_3D_ARB 0x8B5F
+ #define GL_SAMPLER_CUBE_ARB 0x8B60
+ #define GL_SAMPLER_1D_SHADOW_ARB 0x8B61
+ #define GL_SAMPLER_2D_SHADOW_ARB 0x8B62
+ #define GL_SAMPLER_2D_RECT_ARB 0x8B63
+ #define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64
+ #define GL_OBJECT_DELETE_STATUS_ARB 0x8B80
+ #define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81
+ #define GL_OBJECT_LINK_STATUS_ARB 0x8B82
+ #define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83
+ #define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84
+ #define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85
+ #define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86
+ #define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87
+ #define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88
+#endif
+
+/* ----------------------------------------------------------------------------
+ GL_ARB_vertex_shader
+---------------------------------------------------------------------------- */
+#ifdef GL_ARB_vertex_shader
+ #define GL_VERTEX_SHADER_ARB 0x8B31
+ #define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A
+ #define GL_MAX_VARYING_FLOATS_ARB 0x8B4B
+ #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C
+ #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D
+ #define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89
+ #define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
+#endif
+
+
+/* ----------------------------------------------------------------------------
+ GL_ARB_fragment_shader
+---------------------------------------------------------------------------- */
+#ifdef GL_ARB_fragment_shader
+ #define GL_FRAGMENT_SHADER_ARB 0x8B30
+ #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49
+ #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
+#endif
+
+
+/* ----------------------------------------------------------------------------
+ GL_ARB_depth_texture
+---------------------------------------------------------------------------- */
+#ifndef GL_ARB_depth_texture
+ #define GL_DEPTH_COMPONENT16_ARB 0x81A5
+ #define GL_DEPTH_COMPONENT24_ARB 0x81A6
+ #define GL_DEPTH_COMPONENT32_ARB 0x81A7
+ #define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A
+ #define GL_DEPTH_TEXTURE_MODE_ARB 0x884B
+#endif
+
+
+#endif//__ARB_MULTITEXTURE_H__
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
new file mode 100644
index 00000000000..d96df751b85
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
@@ -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) 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 *.cpp)
+
+SET(INC
+ ../../../../source/kernel/gen_system
+ ../../../../intern/string
+ ../../../../intern/moto/include
+ ../../../../source/gameengine/Rasterizer
+)
+
+BLENDERLIB(bf_oglrasterizer "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_oglrasterizer', Split(sources), Split(incs), [], libtype=['game','player'], priority=[40, 120] )
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/EXT_separate_specular_color.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/EXT_separate_specular_color.h
new file mode 100644
index 00000000000..5a9d8f32a87
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/EXT_separate_specular_color.h
@@ -0,0 +1,12 @@
+#ifndef GL_EXT_separate_specular_color
+#define GL_EXT_separate_specular_color 1
+#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8
+#define GL_SINGLE_COLOR_EXT 0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA
+#endif
+
+#ifndef GL_VERSION_1_2
+#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8
+#define GL_SINGLE_COLOR 0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR 0x81FA
+#endif
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile
new file mode 100644
index 00000000000..40f3fc50005
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/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 *****
+#
+# Bounce make to subdirectories.
+#
+
+LIBNAME = OpenGLrasterizer
+DIR = $(OCGDIR)/gameengine/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I../../../kernel/gen_system
+CPPFLAGS += -I..
+ifeq ($(OS),darwin)
+ CPPFLAGS += -fpascal-strings
+endif
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp
new file mode 100644
index 00000000000..26b00f02e7d
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp
@@ -0,0 +1,691 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/*
+ The extension manager's job is to link at runtime OpenGL extension
+ functions.
+
+ Since the various platform have different methods of finding a fn
+ pointer, this file attempts to encapsulate all that, so it gets a
+ little messy. Hopefully we can
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+# include <windows.h>
+
+# include <GL/gl.h>
+
+#elif defined(__APPLE__)
+# include <Carbon/Carbon.h>
+# define GL_GLEXT_LEGACY 1
+# include <OpenGL/gl.h>
+
+#else /* UNIX */
+# include <GL/gl.h>
+# include <GL/glx.h>
+
+# include <dlfcn.h>
+#endif
+
+#include <vector>
+#include <iostream>
+#include <algorithm>
+#include <bitset>
+
+#include "STR_String.h"
+
+#include "RAS_GLExtensionManager.h"
+
+/* -----------------------------------------------------------------------------
+
+ Platform specific functions section.
+
+ Required Functions:
+ static void bglInitEntryPoints (void) -- Loads the GL library
+ static void bglDeallocEntryPoints (void) -- Frees the GL library
+ static void *bglGetProcAddress(const GLubyte* entry) -- Finds the address of
+ the GL function entry
+
+*/
+#if defined(BGL_NO_EXTENSIONS)
+static void bglInitEntryPoints (void) {}
+static void bglDeallocEntryPoints (void) {}
+
+static void *bglGetProcAddress(const GLubyte* entry)
+{
+ /* No Extensions! */
+ return NULL;
+}
+#elif defined(__APPLE__)
+/* http://developer.apple.com/qa/qa2001/qa1188.html */
+CFBundleRef gBundleRefOpenGL = NULL;
+
+// -------------------------
+
+static OSStatus bglInitEntryPoints (void)
+{
+ OSStatus err = noErr;
+ const Str255 frameworkName = "\pOpenGL.framework";
+ FSRefParam fileRefParam;
+ FSRef fileRef;
+ CFURLRef bundleURLOpenGL;
+
+ memset(&fileRefParam, 0, sizeof(fileRefParam));
+ memset(&fileRef, 0, sizeof(fileRef));
+
+ fileRefParam.ioNamePtr = frameworkName;
+ fileRefParam.newRef = &fileRef;
+
+ // Frameworks directory/folder
+ err = FindFolder (kSystemDomain, kFrameworksFolderType, false,
+ &fileRefParam.ioVRefNum, (SInt32*)&fileRefParam.ioDirID);
+ if (noErr != err) {
+ DebugStr ((unsigned char *)"\pCould not find frameworks folder");
+ return err;
+ }
+ err = PBMakeFSRefSync (&fileRefParam); // make FSRef for folder
+ if (noErr != err) {
+ DebugStr ((unsigned char *)"\pCould make FSref to frameworks folder");
+ return err;
+ }
+ // create URL to folder
+ bundleURLOpenGL = CFURLCreateFromFSRef (kCFAllocatorDefault,
+ &fileRef);
+ if (!bundleURLOpenGL) {
+ DebugStr ((unsigned char *)"\pCould create OpenGL Framework bundle URL");
+ return paramErr;
+ }
+ // create ref to GL's bundle
+ gBundleRefOpenGL = CFBundleCreate (kCFAllocatorDefault,
+ bundleURLOpenGL);
+ if (!gBundleRefOpenGL) {
+ DebugStr ((unsigned char *)"\pCould not create OpenGL Framework bundle");
+ return paramErr;
+ }
+ CFRelease (bundleURLOpenGL); // release created bundle
+ // if the code was successfully loaded, look for our function.
+ if (!CFBundleLoadExecutable (gBundleRefOpenGL)) {
+ DebugStr ((unsigned char *)"\pCould not load MachO executable");
+ return paramErr;
+ }
+ return err;
+}
+
+// -------------------------
+
+static void bglDeallocEntryPoints (void)
+{
+ if (gBundleRefOpenGL != NULL) {
+ // unload the bundle's code.
+ CFBundleUnloadExecutable (gBundleRefOpenGL);
+ CFRelease (gBundleRefOpenGL);
+ gBundleRefOpenGL = NULL;
+ }
+}
+
+// -------------------------
+
+/*unused*/
+static void * bglGetProcAddress (const GLubyte * pszProc)
+{
+ if (!gBundleRefOpenGL)
+ return NULL;
+
+ return CFBundleGetFunctionPointerForName (gBundleRefOpenGL,
+ CFStringCreateWithCStringNoCopy (NULL,
+ (const char *) pszProc, CFStringGetSystemEncoding (), NULL));
+}
+#elif defined(GLX_ARB_get_proc_address)
+/* Not all glx.h define PFNGLXGETPROCADDRESSARBPROC !
+ We define our own if needed. */
+#ifdef HAVE_PFNGLXGETPROCADDRESSARBPROC
+#define PFNBGLXGETPROCADDRESSARBPROC PFNGLXGETPROCADDRESSARBPROC
+#else
+typedef void (*(*PFNBGLXGETPROCADDRESSARBPROC)(const GLubyte *procname))();
+#endif
+
+void *_getProcAddress(const GLubyte *procName) { return NULL; }
+PFNBGLXGETPROCADDRESSARBPROC bglGetProcAddress;
+
+
+//weird bug related to combination of pthreads,libGL and dlopen
+//cannot call dlclose in such environment, causes crashes
+//so try to keep a global handle to libGL
+void* libGL = 0;
+
+static void bglInitEntryPoints (void)
+{
+ Display *dpy = glXGetCurrentDisplay();
+ std::vector<STR_String> Xextensions = STR_String(glXQueryExtensionsString(dpy, DefaultScreen(dpy))).Explode(' ');
+ if (std::find(Xextensions.begin(), Xextensions.end(), "GLX_ARB_get_proc_address") != Xextensions.end())
+ {
+ if (!libGL)
+ {
+ libGL = dlopen("libGL.so", RTLD_LAZY|RTLD_GLOBAL);
+ if (libGL)
+ bglGetProcAddress = (PFNBGLXGETPROCADDRESSARBPROC) (dlsym(libGL, "glXGetProcAddressARB"));
+ else
+ std::cout << "Error: " << dlerror() << std::endl;
+
+ // dlclose(libGL);
+ if (!bglGetProcAddress)
+ bglGetProcAddress = (PFNBGLXGETPROCADDRESSARBPROC) _getProcAddress;
+
+ // --
+ if(!bglGetProcAddress)
+ std::cout << "Error: unable to find _getProcAddress in libGL" << std::endl;
+ }
+ }
+}
+
+static void bglDeallocEntryPoints (void) {}
+
+#elif defined(WIN32)
+static void bglInitEntryPoints (void) {}
+static void bglDeallocEntryPoints (void) {}
+
+#define bglGetProcAddress(entry) wglGetProcAddress((LPCSTR) entry)
+
+#else /* Unknown Platform - disable extensions */
+static void bglInitEntryPoints (void) {}
+static void bglDeallocEntryPoints (void) {}
+
+static void *bglGetProcAddress(const GLubyte* entry)
+{
+ /* No Extensions! */
+ return NULL;
+}
+
+#endif /* End Platform Specific */
+
+/* -----------------------------------------------------------------------------
+
+ GL Extension Manager.
+*/
+ /* Bit array of available extensions */
+static std::bitset<bgl::NUM_EXTENSIONS> enabled_extensions;
+static std::vector<STR_String> extensions;
+static int m_debug;
+
+static void LinkExtensions();
+
+static void EnableExtension(bgl::ExtensionName name)
+{
+ unsigned int num = (unsigned int) name;
+ if (num < bgl::NUM_EXTENSIONS)
+ enabled_extensions.set(num);
+}
+
+
+static bool QueryExtension(STR_String extension_name)
+{
+ return std::find(extensions.begin(), extensions.end(), extension_name) != extensions.end();
+}
+
+namespace bgl
+{
+
+void InitExtensions(int debug)
+{
+ m_debug = debug;
+ bglInitEntryPoints (); //init bundle
+ EnableExtension(_BGL_TEST);
+ LinkExtensions();
+ bglDeallocEntryPoints();
+}
+
+bool QueryExtension(ExtensionName name)
+{
+ unsigned int num = (unsigned int) name;
+ if (num < NUM_EXTENSIONS)
+ return enabled_extensions[num];
+
+ return false;
+}
+
+bool QueryVersion(int major, int minor)
+{
+ static int gl_major = 0;
+ static int gl_minor = 0;
+
+ if (gl_major == 0)
+ {
+ const char *gl_version_str = (const char *) glGetString(GL_VERSION);
+ if (!gl_version_str)
+ return false;
+ STR_String gl_version = STR_String(gl_version_str);
+ int i = gl_version.Find('.');
+ gl_major = gl_version.Left(i).ToInt();
+ gl_minor = gl_version.Mid(i+1, gl_version.FindOneOf(". ", i+1) - i - 1).ToInt();
+
+ static bool doQueryVersion = m_debug;
+ if (doQueryVersion)
+ {
+ doQueryVersion = false;
+ std::cout << "GL_VERSION: " << gl_major << "." << gl_minor << " (" << gl_version << ")" << std::endl;
+ }
+ }
+
+ if (gl_major > major)
+ return true;
+
+ if (gl_major == major && gl_minor >= minor)
+ return true;
+
+ return false;
+}
+
+
+/*******************************************************************************
+1. Extension function entry points go here
+
+Need to #ifdef (compile time test for extension)
+Add null functions if appropriate
+
+Some extensions have been incorporated into the core GL, eg Multitexture was
+added in GL v1.1. If Blender calls one of these functions before they are
+linked, it will crash. Even worse, if Blender *indirectly* calls one of these
+functions, (ie the GL implementation calls them itself) Blender will crash.
+
+We fix this by adding them to the bgl namespace - the functions are now
+private to the gameengine. Code can transparently use extensions by adding:
+
+using namespace bgl;
+
+to their source. Cunning like a weasel.
+
+ ******************************************************************************/
+
+#if defined(PFNGLPNTRIANGLESIATIPROC)
+PFNGLPNTRIANGLESIATIPROC glPNTrianglesiATI;
+PFNGLPNTRIANGLESFATIPROC glPNTrianglesfATI;
+#endif
+
+BL_EXTInfo RAS_EXT_support;
+
+
+#ifdef GL_ARB_multitexture
+int max_texture_units = 2;
+ PFNGLACTIVETEXTUREARBPROC blActiveTextureARB;
+ PFNGLCLIENTACTIVETEXTUREARBPROC blClientActiveTextureARB;
+ PFNGLMULTITEXCOORD1DARBPROC blMultiTexCoord1dARB;
+ PFNGLMULTITEXCOORD1DVARBPROC blMultiTexCoord1dvARB;
+ PFNGLMULTITEXCOORD1FARBPROC blMultiTexCoord1fARB;
+ PFNGLMULTITEXCOORD1FVARBPROC blMultiTexCoord1fvARB;
+ PFNGLMULTITEXCOORD1IARBPROC blMultiTexCoord1iARB;
+ PFNGLMULTITEXCOORD1IVARBPROC blMultiTexCoord1ivARB;
+ PFNGLMULTITEXCOORD1SARBPROC blMultiTexCoord1sARB;
+ PFNGLMULTITEXCOORD1SVARBPROC blMultiTexCoord1svARB;
+ PFNGLMULTITEXCOORD2DARBPROC blMultiTexCoord2dARB;
+ PFNGLMULTITEXCOORD2DVARBPROC blMultiTexCoord2dvARB;
+ PFNGLMULTITEXCOORD2FARBPROC blMultiTexCoord2fARB;
+ PFNGLMULTITEXCOORD2FVARBPROC blMultiTexCoord2fvARB;
+ PFNGLMULTITEXCOORD2IARBPROC blMultiTexCoord2iARB;
+ PFNGLMULTITEXCOORD2IVARBPROC blMultiTexCoord2ivARB;
+ PFNGLMULTITEXCOORD2SARBPROC blMultiTexCoord2sARB;
+ PFNGLMULTITEXCOORD2SVARBPROC blMultiTexCoord2svARB;
+ PFNGLMULTITEXCOORD3DARBPROC blMultiTexCoord3dARB;
+ PFNGLMULTITEXCOORD3DVARBPROC blMultiTexCoord3dvARB;
+ PFNGLMULTITEXCOORD3FARBPROC blMultiTexCoord3fARB;
+ PFNGLMULTITEXCOORD3FVARBPROC blMultiTexCoord3fvARB;
+ PFNGLMULTITEXCOORD3IARBPROC blMultiTexCoord3iARB;
+ PFNGLMULTITEXCOORD3IVARBPROC blMultiTexCoord3ivARB;
+ PFNGLMULTITEXCOORD3SARBPROC blMultiTexCoord3sARB;
+ PFNGLMULTITEXCOORD3SVARBPROC blMultiTexCoord3svARB;
+ PFNGLMULTITEXCOORD4DARBPROC blMultiTexCoord4dARB;
+ PFNGLMULTITEXCOORD4DVARBPROC blMultiTexCoord4dvARB;
+ PFNGLMULTITEXCOORD4FARBPROC blMultiTexCoord4fARB;
+ PFNGLMULTITEXCOORD4FVARBPROC blMultiTexCoord4fvARB;
+ PFNGLMULTITEXCOORD4IARBPROC blMultiTexCoord4iARB;
+ PFNGLMULTITEXCOORD4IVARBPROC blMultiTexCoord4ivARB;
+ PFNGLMULTITEXCOORD4SARBPROC blMultiTexCoord4sARB;
+ PFNGLMULTITEXCOORD4SVARBPROC blMultiTexCoord4svARB;
+#endif
+
+#ifdef GL_ARB_shader_objects
+ PFNGLDELETEOBJECTARBPROC blDeleteObjectARB;
+ PFNGLGETHANDLEARBPROC blGetHandleARB;
+ PFNGLDETACHOBJECTARBPROC blDetachObjectARB;
+ PFNGLCREATESHADEROBJECTARBPROC blCreateShaderObjectARB;
+ PFNGLSHADERSOURCEARBPROC blShaderSourceARB;
+ PFNGLCOMPILESHADERARBPROC blCompileShaderARB;
+ PFNGLCREATEPROGRAMOBJECTARBPROC blCreateProgramObjectARB;
+ PFNGLATTACHOBJECTARBPROC blAttachObjectARB;
+ PFNGLLINKPROGRAMARBPROC blLinkProgramARB;
+ PFNGLUSEPROGRAMOBJECTARBPROC blUseProgramObjectARB;
+ PFNGLVALIDATEPROGRAMARBPROC blValidateProgramARB;
+ PFNGLUNIFORM1FARBPROC blUniform1fARB;
+ PFNGLUNIFORM2FARBPROC blUniform2fARB;
+ PFNGLUNIFORM3FARBPROC blUniform3fARB;
+ PFNGLUNIFORM4FARBPROC blUniform4fARB;
+ PFNGLUNIFORM1IARBPROC blUniform1iARB;
+ PFNGLUNIFORM2IARBPROC blUniform2iARB;
+ PFNGLUNIFORM3IARBPROC blUniform3iARB;
+ PFNGLUNIFORM4IARBPROC blUniform4iARB;
+ PFNGLUNIFORM1FVARBPROC blUniform1fvARB;
+ PFNGLUNIFORM2FVARBPROC blUniform2fvARB;
+ PFNGLUNIFORM3FVARBPROC blUniform3fvARB;
+ PFNGLUNIFORM4FVARBPROC blUniform4fvARB;
+ PFNGLUNIFORM1IVARBPROC blUniform1ivARB;
+ PFNGLUNIFORM2IVARBPROC blUniform2ivARB;
+ PFNGLUNIFORM3IVARBPROC blUniform3ivARB;
+ PFNGLUNIFORM4IVARBPROC blUniform4ivARB;
+ PFNGLUNIFORMMATRIX2FVARBPROC blUniformMatrix2fvARB;
+ PFNGLUNIFORMMATRIX3FVARBPROC blUniformMatrix3fvARB;
+ PFNGLUNIFORMMATRIX4FVARBPROC blUniformMatrix4fvARB;
+ PFNGLGETOBJECTPARAMETERFVARBPROC blGetObjectParameterfvARB;
+ PFNGLGETOBJECTPARAMETERIVARBPROC blGetObjectParameterivARB;
+ PFNGLGETINFOLOGARBPROC blGetInfoLogARB;
+ PFNGLGETATTACHEDOBJECTSARBPROC blGetAttachedObjectsARB;
+ PFNGLGETUNIFORMLOCATIONARBPROC blGetUniformLocationARB;
+ PFNGLGETACTIVEUNIFORMARBPROC blGetActiveUniformARB;
+ PFNGLGETUNIFORMFVARBPROC blGetUniformfvARB;
+ PFNGLGETUNIFORMIVARBPROC blGetUniformivARB;
+ PFNGLGETSHADERSOURCEARBPROC blGetShaderSourceARB;
+#endif
+
+#ifdef GL_ARB_vertex_shader
+PFNGLBINDATTRIBLOCATIONARBPROC blBindAttribLocationARB;
+PFNGLGETACTIVEATTRIBARBPROC blGetActiveAttribARB;
+PFNGLGETATTRIBLOCATIONARBPROC blGetAttribLocationARB;
+#endif
+
+#ifdef GL_ARB_vertex_program
+ PFNGLVERTEXATTRIB1FARBPROC blVertexAttrib1fARB;
+ PFNGLVERTEXATTRIB1FVARBPROC blVertexAttrib1fvARB;
+ PFNGLVERTEXATTRIB2FARBPROC blVertexAttrib2fARB;
+ PFNGLVERTEXATTRIB2FVARBPROC blVertexAttrib2fvARB;
+ PFNGLVERTEXATTRIB3FARBPROC blVertexAttrib3fARB;
+ PFNGLVERTEXATTRIB3FVARBPROC blVertexAttrib3fvARB;
+ PFNGLVERTEXATTRIB4FARBPROC blVertexAttrib4fARB;
+ PFNGLVERTEXATTRIB4FVARBPROC blVertexAttrib4fvARB;
+ PFNGLGETPROGRAMSTRINGARBPROC blGetProgramStringARB;
+ PFNGLGETVERTEXATTRIBDVARBPROC blGetVertexAttribdvARB;
+ PFNGLGETVERTEXATTRIBFVARBPROC blGetVertexAttribfvARB;
+ PFNGLGETVERTEXATTRIBIVARBPROC blGetVertexAttribivARB;
+#endif
+
+ /*
+#ifdef GL_EXT_compiled_vertex_array
+ PFNGLLOCKARRAYSEXTPROC blLockArraysEXT;
+ PFNGLUNLOCKARRAYSEXTPROC blUnlockArraysEXT;
+#endif
+*/
+
+} // namespace bgl
+
+using namespace bgl;
+/*******************************************************************************
+2. Query extension functions here
+
+Need to #ifdef (compile time test for extension)
+Use QueryExtension("GL_EXT_name") to test at runtime.
+Use bglGetProcAddress to find entry point
+Use EnableExtension(_GL_EXT_...) to allow Blender to use the extension.
+
+ ******************************************************************************/
+static void LinkExtensions()
+{
+ static bool doDebugMessages = m_debug;
+ extensions = STR_String((const char *) glGetString(GL_EXTENSIONS)).Explode(' ');
+ RAS_EXT_support = BL_EXTInfo();
+
+#if defined(PFNGLPNTRIANGLESIATIPROC)
+ if (QueryExtension("GL_ATI_pn_triangles"))
+ {
+ glPNTrianglesiATI = reinterpret_cast<PFNGLPNTRIANGLESIATIPROC>(bglGetProcAddress((const GLubyte *) "glPNTrianglesiATI"));
+ glPNTrianglesfATI = reinterpret_cast<PFNGLPNTRIANGLESFATIPROC>(bglGetProcAddress((const GLubyte *) "glPNTrianglesfATI"));
+ if (glPNTrianglesiATI && glPNTrianglesfATI) {
+ EnableExtension(_GL_ATI_pn_triangles);
+ if (doDebugMessages)
+ std::cout << "Enabled GL_ATI_pn_triangles" << std::endl;
+ } else {
+ std::cout << "ERROR: GL_ATI_pn_triangles implementation is broken!" << std::endl;
+ }
+ }
+#endif
+
+#ifdef GL_ARB_texture_env_combine
+ if (QueryExtension("GL_ARB_texture_env_combine"))
+ {
+ EnableExtension(_GL_ARB_texture_env_combine);
+ RAS_EXT_support._ARB_texture_env_combine = 1;
+ if (doDebugMessages)
+ {
+ std::cout << "Detected GL_ARB_texture_env_combine" << std::endl;
+ }
+ }
+#endif
+
+#ifdef GL_ARB_texture_cube_map
+ if (QueryExtension("GL_ARB_texture_cube_map"))
+ {
+ EnableExtension(_GL_ARB_texture_cube_map);
+ RAS_EXT_support._ARB_texture_cube_map = 1;
+ if (doDebugMessages)
+ std::cout << "Detected GL_ARB_texture_cube_map" << std::endl;
+ }
+#endif
+
+#ifdef GL_ARB_multitexture
+ if (QueryExtension("GL_ARB_multitexture"))
+ {
+ bgl::blActiveTextureARB = reinterpret_cast<PFNGLACTIVETEXTUREARBPROC>(bglGetProcAddress((const GLubyte *) "glActiveTextureARB"));
+ bgl::blClientActiveTextureARB = reinterpret_cast<PFNGLCLIENTACTIVETEXTUREARBPROC>(bglGetProcAddress((const GLubyte *) "glClientActiveTextureARB"));
+ bgl::blMultiTexCoord1dARB = reinterpret_cast<PFNGLMULTITEXCOORD1DARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord1dARB"));
+ bgl::blMultiTexCoord1dvARB = reinterpret_cast<PFNGLMULTITEXCOORD1DVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord1dvARB"));
+ bgl::blMultiTexCoord1fARB = reinterpret_cast<PFNGLMULTITEXCOORD1FARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord1fARB"));
+ bgl::blMultiTexCoord1fvARB = reinterpret_cast<PFNGLMULTITEXCOORD1FVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord1fvARB"));
+ bgl::blMultiTexCoord1iARB = reinterpret_cast<PFNGLMULTITEXCOORD1IARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord1iARB"));
+ bgl::blMultiTexCoord1ivARB = reinterpret_cast<PFNGLMULTITEXCOORD1IVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord1ivARB"));
+ bgl::blMultiTexCoord1sARB = reinterpret_cast<PFNGLMULTITEXCOORD1SARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord1sARB"));
+ bgl::blMultiTexCoord1svARB = reinterpret_cast<PFNGLMULTITEXCOORD1SVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord1svARB"));
+ bgl::blMultiTexCoord2dARB = reinterpret_cast<PFNGLMULTITEXCOORD2DARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord2dARB"));
+ bgl::blMultiTexCoord2dvARB = reinterpret_cast<PFNGLMULTITEXCOORD2DVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord2dvARB"));
+ bgl::blMultiTexCoord2fARB = reinterpret_cast<PFNGLMULTITEXCOORD2FARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord2fARB"));
+ bgl::blMultiTexCoord2fvARB = reinterpret_cast<PFNGLMULTITEXCOORD2FVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord2fvARB"));
+ bgl::blMultiTexCoord2iARB = reinterpret_cast<PFNGLMULTITEXCOORD2IARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord2iARB"));
+ bgl::blMultiTexCoord2ivARB = reinterpret_cast<PFNGLMULTITEXCOORD2IVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord2ivARB"));
+ bgl::blMultiTexCoord2sARB = reinterpret_cast<PFNGLMULTITEXCOORD2SARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord2sARB"));
+ bgl::blMultiTexCoord2svARB = reinterpret_cast<PFNGLMULTITEXCOORD2SVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord2svARB"));
+ bgl::blMultiTexCoord3dARB = reinterpret_cast<PFNGLMULTITEXCOORD3DARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord3dARB"));
+ bgl::blMultiTexCoord3dvARB = reinterpret_cast<PFNGLMULTITEXCOORD3DVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord3dvARB"));
+ bgl::blMultiTexCoord3fARB = reinterpret_cast<PFNGLMULTITEXCOORD3FARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord3fARB"));
+ bgl::blMultiTexCoord3fvARB = reinterpret_cast<PFNGLMULTITEXCOORD3FVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord3fvARB"));
+ bgl::blMultiTexCoord3iARB = reinterpret_cast<PFNGLMULTITEXCOORD3IARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord3iARB"));
+ bgl::blMultiTexCoord3ivARB = reinterpret_cast<PFNGLMULTITEXCOORD3IVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord3ivARB"));
+ bgl::blMultiTexCoord3sARB = reinterpret_cast<PFNGLMULTITEXCOORD3SARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord3sARB"));
+ bgl::blMultiTexCoord3svARB = reinterpret_cast<PFNGLMULTITEXCOORD3SVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord3svARB"));
+ bgl::blMultiTexCoord4dARB = reinterpret_cast<PFNGLMULTITEXCOORD4DARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord4dARB"));
+ bgl::blMultiTexCoord4dvARB = reinterpret_cast<PFNGLMULTITEXCOORD4DVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord4dvARB"));
+ bgl::blMultiTexCoord4fARB = reinterpret_cast<PFNGLMULTITEXCOORD4FARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord4fARB"));
+ bgl::blMultiTexCoord4fvARB = reinterpret_cast<PFNGLMULTITEXCOORD4FVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord4fvARB"));
+ bgl::blMultiTexCoord4iARB = reinterpret_cast<PFNGLMULTITEXCOORD4IARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord4iARB"));
+ bgl::blMultiTexCoord4ivARB = reinterpret_cast<PFNGLMULTITEXCOORD4IVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord4ivARB"));
+ bgl::blMultiTexCoord4sARB = reinterpret_cast<PFNGLMULTITEXCOORD4SARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord4sARB"));
+ bgl::blMultiTexCoord4svARB = reinterpret_cast<PFNGLMULTITEXCOORD4SVARBPROC>(bglGetProcAddress((const GLubyte *) "glMultiTexCoord4svARB"));
+ if (bgl::blActiveTextureARB && bgl::blClientActiveTextureARB && bgl::blMultiTexCoord1dARB && bgl::blMultiTexCoord1dvARB && bgl::blMultiTexCoord1fARB && bgl::blMultiTexCoord1fvARB && bgl::blMultiTexCoord1iARB && bgl::blMultiTexCoord1ivARB && bgl::blMultiTexCoord1sARB && bgl::blMultiTexCoord1svARB && bgl::blMultiTexCoord2dARB && bgl::blMultiTexCoord2dvARB && bgl::blMultiTexCoord2fARB && bgl::blMultiTexCoord2fvARB && bgl::blMultiTexCoord2iARB && bgl::blMultiTexCoord2ivARB && bgl::blMultiTexCoord2sARB && bgl::blMultiTexCoord2svARB && bgl::blMultiTexCoord3dARB && bgl::blMultiTexCoord3dvARB && bgl::blMultiTexCoord3fARB && bgl::blMultiTexCoord3fvARB && bgl::blMultiTexCoord3iARB && bgl::blMultiTexCoord3ivARB && bgl::blMultiTexCoord3sARB && bgl::blMultiTexCoord3svARB && bgl::blMultiTexCoord4dARB && bgl::blMultiTexCoord4dvARB && bgl::blMultiTexCoord4fARB && bgl::blMultiTexCoord4fvARB && bgl::blMultiTexCoord4iARB && bgl::blMultiTexCoord4ivARB && bgl::blMultiTexCoord4sARB && bgl::blMultiTexCoord4svARB) {
+ EnableExtension(_GL_ARB_multitexture);
+ RAS_EXT_support._ARB_multitexture = 1;
+ if (doDebugMessages)
+ std::cout << "Enabled GL_ARB_multitexture" << std::endl;
+ } else {
+ std::cout << "ERROR: GL_ARB_multitexture implementation is broken!" << std::endl;
+ }
+ }
+#endif
+
+#if GL_ARB_shader_objects
+ if (QueryExtension("GL_ARB_shader_objects"))
+ {
+ bgl::blDeleteObjectARB = reinterpret_cast<PFNGLDELETEOBJECTARBPROC>(bglGetProcAddress((const GLubyte *) "glDeleteObjectARB"));
+ bgl::blGetHandleARB = reinterpret_cast<PFNGLGETHANDLEARBPROC>(bglGetProcAddress((const GLubyte *) "glGetHandleARB"));
+ bgl::blDetachObjectARB = reinterpret_cast<PFNGLDETACHOBJECTARBPROC>(bglGetProcAddress((const GLubyte *) "glDetachObjectARB"));
+ bgl::blCreateShaderObjectARB = reinterpret_cast<PFNGLCREATESHADEROBJECTARBPROC>(bglGetProcAddress((const GLubyte *) "glCreateShaderObjectARB"));
+ bgl::blShaderSourceARB = reinterpret_cast<PFNGLSHADERSOURCEARBPROC>(bglGetProcAddress((const GLubyte *) "glShaderSourceARB"));
+ bgl::blCompileShaderARB = reinterpret_cast<PFNGLCOMPILESHADERARBPROC>(bglGetProcAddress((const GLubyte *) "glCompileShaderARB"));
+ bgl::blCreateProgramObjectARB = reinterpret_cast<PFNGLCREATEPROGRAMOBJECTARBPROC>(bglGetProcAddress((const GLubyte *) "glCreateProgramObjectARB"));
+ bgl::blAttachObjectARB = reinterpret_cast<PFNGLATTACHOBJECTARBPROC>(bglGetProcAddress((const GLubyte *) "glAttachObjectARB"));
+ bgl::blLinkProgramARB = reinterpret_cast<PFNGLLINKPROGRAMARBPROC>(bglGetProcAddress((const GLubyte *) "glLinkProgramARB"));
+ bgl::blUseProgramObjectARB = reinterpret_cast<PFNGLUSEPROGRAMOBJECTARBPROC>(bglGetProcAddress((const GLubyte *) "glUseProgramObjectARB"));
+ bgl::blValidateProgramARB = reinterpret_cast<PFNGLVALIDATEPROGRAMARBPROC>(bglGetProcAddress((const GLubyte *) "glValidateProgramARB"));
+ bgl::blUniform1fARB = reinterpret_cast<PFNGLUNIFORM1FARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform1fARB"));
+ bgl::blUniform2fARB = reinterpret_cast<PFNGLUNIFORM2FARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform2fARB"));
+ bgl::blUniform3fARB = reinterpret_cast<PFNGLUNIFORM3FARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform3fARB"));
+ bgl::blUniform4fARB = reinterpret_cast<PFNGLUNIFORM4FARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform4fARB"));
+ bgl::blUniform1iARB = reinterpret_cast<PFNGLUNIFORM1IARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform1iARB"));
+ bgl::blUniform2iARB = reinterpret_cast<PFNGLUNIFORM2IARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform2iARB"));
+ bgl::blUniform3iARB = reinterpret_cast<PFNGLUNIFORM3IARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform3iARB"));
+ bgl::blUniform4iARB = reinterpret_cast<PFNGLUNIFORM4IARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform4iARB"));
+ bgl::blUniform1fvARB = reinterpret_cast<PFNGLUNIFORM1FVARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform1fvARB"));
+ bgl::blUniform2fvARB = reinterpret_cast<PFNGLUNIFORM2FVARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform2fvARB"));
+ bgl::blUniform3fvARB = reinterpret_cast<PFNGLUNIFORM3FVARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform3fvARB"));
+ bgl::blUniform4fvARB = reinterpret_cast<PFNGLUNIFORM4FVARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform4fvARB"));
+ bgl::blUniform1ivARB = reinterpret_cast<PFNGLUNIFORM1IVARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform1ivARB"));
+ bgl::blUniform2ivARB = reinterpret_cast<PFNGLUNIFORM2IVARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform2ivARB"));
+ bgl::blUniform3ivARB = reinterpret_cast<PFNGLUNIFORM3IVARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform3ivARB"));
+ bgl::blUniform4ivARB = reinterpret_cast<PFNGLUNIFORM4IVARBPROC>(bglGetProcAddress((const GLubyte *) "glUniform4ivARB"));
+ bgl::blUniformMatrix2fvARB = reinterpret_cast<PFNGLUNIFORMMATRIX2FVARBPROC>(bglGetProcAddress((const GLubyte *) "glUniformMatrix2fvARB"));
+ bgl::blUniformMatrix3fvARB = reinterpret_cast<PFNGLUNIFORMMATRIX3FVARBPROC>(bglGetProcAddress((const GLubyte *) "glUniformMatrix3fvARB"));
+ bgl::blUniformMatrix4fvARB = reinterpret_cast<PFNGLUNIFORMMATRIX4FVARBPROC>(bglGetProcAddress((const GLubyte *) "glUniformMatrix4fvARB"));
+ bgl::blGetObjectParameterfvARB = reinterpret_cast<PFNGLGETOBJECTPARAMETERFVARBPROC>(bglGetProcAddress((const GLubyte *) "glGetObjectParameterfvARB"));
+ bgl::blGetObjectParameterivARB = reinterpret_cast<PFNGLGETOBJECTPARAMETERIVARBPROC>(bglGetProcAddress((const GLubyte *) "glGetObjectParameterivARB"));
+ bgl::blGetInfoLogARB = reinterpret_cast<PFNGLGETINFOLOGARBPROC>(bglGetProcAddress((const GLubyte *) "glGetInfoLogARB"));
+ bgl::blGetAttachedObjectsARB = reinterpret_cast<PFNGLGETATTACHEDOBJECTSARBPROC>(bglGetProcAddress((const GLubyte *) "glGetAttachedObjectsARB"));
+ bgl::blGetUniformLocationARB = reinterpret_cast<PFNGLGETUNIFORMLOCATIONARBPROC>(bglGetProcAddress((const GLubyte *) "glGetUniformLocationARB"));
+ bgl::blGetActiveUniformARB = reinterpret_cast<PFNGLGETACTIVEUNIFORMARBPROC>(bglGetProcAddress((const GLubyte *) "glGetActiveUniformARB"));
+ bgl::blGetUniformfvARB = reinterpret_cast<PFNGLGETUNIFORMFVARBPROC>(bglGetProcAddress((const GLubyte *) "glGetUniformfvARB"));
+ bgl::blGetUniformivARB = reinterpret_cast<PFNGLGETUNIFORMIVARBPROC>(bglGetProcAddress((const GLubyte *) "glGetUniformivARB"));
+ bgl::blGetShaderSourceARB = reinterpret_cast<PFNGLGETSHADERSOURCEARBPROC>(bglGetProcAddress((const GLubyte *) "glGetShaderSourceARB"));
+ if (bgl::blDeleteObjectARB && bgl::blGetHandleARB && bgl::blDetachObjectARB && bgl::blCreateShaderObjectARB && bgl::blShaderSourceARB && bgl::blCompileShaderARB && bgl::blCreateProgramObjectARB && bgl::blAttachObjectARB && bgl::blLinkProgramARB && bgl::blUseProgramObjectARB && bgl::blValidateProgramARB && bgl::blUniform1fARB && bgl::blUniform2fARB && bgl::blUniform3fARB && bgl::blUniform4fARB && bgl::blUniform1iARB && bgl::blUniform2iARB && bgl::blUniform3iARB && bgl::blUniform4iARB && bgl::blUniform1fvARB && bgl::blUniform2fvARB && bgl::blUniform3fvARB && bgl::blUniform4fvARB && bgl::blUniform1ivARB && bgl::blUniform2ivARB && bgl::blUniform3ivARB && bgl::blUniform4ivARB && bgl::blUniformMatrix2fvARB && bgl::blUniformMatrix3fvARB && bgl::blUniformMatrix4fvARB && bgl::blGetObjectParameterfvARB && bgl::blGetObjectParameterivARB && bgl::blGetInfoLogARB && bgl::blGetAttachedObjectsARB && bgl::blGetUniformLocationARB && bgl::blGetActiveUniformARB && bgl::blGetUniformfvARB && bgl::blGetUniformivARB && bgl::blGetShaderSourceARB) {
+ EnableExtension(_GL_ARB_shader_objects);
+ RAS_EXT_support._ARB_shader_objects =1;
+ if (doDebugMessages)
+ std::cout << "Enabled GL_ARB_shader_objects" << std::endl;
+ } else {
+ std::cout << "ERROR: GL_ARB_shader_objects implementation is broken!" << std::endl;
+ }
+ }
+#endif
+
+#if GL_ARB_vertex_shader
+ if (QueryExtension("GL_ARB_vertex_shader"))
+ {
+ bgl::blBindAttribLocationARB = reinterpret_cast<PFNGLBINDATTRIBLOCATIONARBPROC>(bglGetProcAddress((const GLubyte *) "glBindAttribLocationARB"));
+ bgl::blGetActiveAttribARB = reinterpret_cast<PFNGLGETACTIVEATTRIBARBPROC>(bglGetProcAddress((const GLubyte *) "glGetActiveAttribARB"));
+ bgl::blGetAttribLocationARB = reinterpret_cast<PFNGLGETATTRIBLOCATIONARBPROC>(bglGetProcAddress((const GLubyte *) "glGetAttribLocationARB"));
+ if (bgl::blBindAttribLocationARB && bgl::blGetActiveAttribARB && bgl::blGetAttribLocationARB) {
+ EnableExtension(_GL_ARB_vertex_shader);
+ RAS_EXT_support._ARB_vertex_shader = 1;
+ if (doDebugMessages)
+ std::cout << "Enabled GL_ARB_vertex_shader" << std::endl;
+ } else {
+ std::cout << "ERROR: GL_ARB_vertex_shader implementation is broken!" << std::endl;
+ }
+ }
+#endif
+
+#ifdef GL_ARB_fragment_shader
+ if (QueryExtension("GL_ARB_fragment_shader"))
+ {
+ EnableExtension(_GL_ARB_fragment_shader);
+ RAS_EXT_support._ARB_fragment_shader = 1;
+ if (doDebugMessages)
+ std::cout << "Detected GL_ARB_fragment_shader" << std::endl;
+ }
+#endif
+
+#if defined(GL_ARB_vertex_program)
+ if (QueryExtension("GL_ARB_vertex_program"))
+ {
+ bgl::blVertexAttrib1fARB = reinterpret_cast<PFNGLVERTEXATTRIB1FARBPROC>(bglGetProcAddress((const GLubyte *) "glVertexAttrib1fARB"));
+ bgl::blVertexAttrib1fvARB = reinterpret_cast<PFNGLVERTEXATTRIB1FVARBPROC>(bglGetProcAddress((const GLubyte *) "glVertexAttrib1fvARB"));
+ bgl::blVertexAttrib2fARB = reinterpret_cast<PFNGLVERTEXATTRIB2FARBPROC>(bglGetProcAddress((const GLubyte *) "glVertexAttrib2fARB"));
+ bgl::blVertexAttrib2fvARB = reinterpret_cast<PFNGLVERTEXATTRIB2FVARBPROC>(bglGetProcAddress((const GLubyte *) "glVertexAttrib2fvARB"));
+ bgl::blVertexAttrib3fARB = reinterpret_cast<PFNGLVERTEXATTRIB3FARBPROC>(bglGetProcAddress((const GLubyte *) "glVertexAttrib3fARB"));
+ bgl::blVertexAttrib3fvARB = reinterpret_cast<PFNGLVERTEXATTRIB3FVARBPROC>(bglGetProcAddress((const GLubyte *) "glVertexAttrib3fvARB"));
+ bgl::blVertexAttrib4fARB = reinterpret_cast<PFNGLVERTEXATTRIB4FARBPROC>(bglGetProcAddress((const GLubyte *) "glVertexAttrib4fARB"));
+ bgl::blVertexAttrib4fvARB = reinterpret_cast<PFNGLVERTEXATTRIB4FVARBPROC>(bglGetProcAddress((const GLubyte *) "glVertexAttrib4fvARB"));
+ bgl::blGetVertexAttribdvARB = reinterpret_cast<PFNGLGETVERTEXATTRIBDVARBPROC>(bglGetProcAddress((const GLubyte *) "glGetVertexAttribdvARB"));
+ bgl::blGetVertexAttribfvARB = reinterpret_cast<PFNGLGETVERTEXATTRIBFVARBPROC>(bglGetProcAddress((const GLubyte *) "glGetVertexAttribfvARB"));
+ bgl::blGetVertexAttribivARB = reinterpret_cast<PFNGLGETVERTEXATTRIBIVARBPROC>(bglGetProcAddress((const GLubyte *) "glGetVertexAttribivARB"));
+ if (bgl::blVertexAttrib1fARB && bgl::blVertexAttrib1fvARB && bgl::blVertexAttrib2fARB && bgl::blVertexAttrib2fvARB && bgl::blVertexAttrib3fARB && bgl::blVertexAttrib3fvARB && bgl::blGetVertexAttribdvARB) {
+ EnableExtension(_GL_ARB_vertex_program);
+ RAS_EXT_support._ARB_vertex_program = 1;
+ if (doDebugMessages)
+ std::cout << "Enabled GL_ARB_vertex_program" << std::endl;
+ } else {
+ std::cout << "ERROR: GL_ARB_vertex_program implementation is broken!" << std::endl;
+ }
+ }
+#endif
+
+
+#ifdef GL_ARB_depth_texture
+ if (QueryExtension("GL_ARB_depth_texture"))
+ {
+ EnableExtension(_GL_ARB_depth_texture);
+ RAS_EXT_support._ARB_depth_texture = 1;
+ if (doDebugMessages)
+ {
+ std::cout << "Detected GL_ARB_depth_texture" << std::endl;
+ }
+ }
+#endif
+/*
+#ifdef GL_EXT_compiled_vertex_array
+ if (QueryExtension("GL_EXT_compiled_vertex_array"))
+ {
+ blLockArraysEXT = reinterpret_cast<PFNGLLOCKARRAYSEXTPROC>(bglGetProcAddress((const GLubyte *) "glLockArraysEXT"));
+ blUnlockArraysEXT = reinterpret_cast<PFNGLUNLOCKARRAYSEXTPROC>(bglGetProcAddress((const GLubyte *) "glUnlockArraysEXT"));
+ if (blLockArraysEXT && blUnlockArraysEXT) {
+ EnableExtension(_GL_EXT_compiled_vertex_array);
+ RAS_EXT_support._EXT_compiled_vertex_array = 1;
+ if (doDebugMessages)
+ std::cout << "Enabled GL_EXT_compiled_vertex_array" << std::endl;
+ } else {
+ std::cout << "ERROR: GL_EXT_compiled_vertex_array implementation is broken!" << std::endl;
+ }
+ }
+#endif
+*/
+ if (QueryExtension("GL_EXT_separate_specular_color"))
+ {
+ EnableExtension(_GL_EXT_separate_specular_color);
+ if (doDebugMessages)
+ std::cout << "Detected GL_EXT_separate_specular_color" << std::endl;
+ }
+
+ doDebugMessages = false;
+}
+
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h
new file mode 100644
index 00000000000..7b1c745832f
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h
@@ -0,0 +1,537 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __RAS_GLEXTENSIONMANAGER_H__
+#define __RAS_GLEXTENSIONMANAGER_H__
+
+
+#ifdef WIN32
+# include <windows.h>
+# include <GL/gl.h>
+
+#elif defined(__APPLE__)
+# define __glext_h_
+# define GL_GLEXT_LEGACY 1
+# include <OpenGL/gl.h>
+# include <OpenGL/glu.h>
+# undef __glext_h_
+
+#else /* UNIX */
+# define __glext_h_
+# include <GL/gl.h>
+# include <GL/glx.h>
+# undef GL_ARB_multitexture // (ubuntu)
+# undef __glext_h_
+#endif
+
+#ifdef __sgi
+# undef GL_ARB_vertex_program
+#endif
+
+#include "glext.h"
+
+#include "EXT_separate_specular_color.h"
+#include "ARB_multitexture.h"
+namespace bgl
+{
+ /**
+ * This is a list of all registered OpenGL extensions.
+ * It is available from:
+ * http://oss.sgi.com/projects/ogl-sample/registry/
+ */
+ typedef enum {
+ /* ARB Extensions */
+ _GL_ARB_imaging,
+ _GL_ARB_multitexture ,
+ _GLX_ARB_get_proc_address ,
+ _GL_ARB_transpose_matrix ,
+ _WGL_ARB_buffer_region ,
+ _GL_ARB_multisample ,
+ _GL_ARB_texture_env_add ,
+ _GL_ARB_texture_cube_map ,
+ _WGL_ARB_extensions_string ,
+ _WGL_ARB_pixel_format ,
+ _WGL_ARB_make_current_read ,
+ _WGL_ARB_pbuffer ,
+ _GL_ARB_texture_compression ,
+ _GL_ARB_texture_border_clamp ,
+ _GL_ARB_point_parameters ,
+ _GL_ARB_vertex_blend ,
+ _GL_ARB_matrix_palette ,
+ _GL_ARB_texture_env_combine ,
+ _GL_ARB_texture_env_crossbar ,
+ _GL_ARB_texture_env_dot3 ,
+ _WGL_ARB_render_texture ,
+ _GL_ARB_texture_mirrored_repeat ,
+ _GL_ARB_depth_texture ,
+ _GL_ARB_shadow ,
+ _GL_ARB_shadow_ambient ,
+ _GL_ARB_window_pos ,
+ _GL_ARB_vertex_program ,
+ _GL_ARB_fragment_program ,
+ _GL_ARB_vertex_buffer_object ,
+ _GL_ARB_occlusion_query ,
+ _GL_ARB_shader_objects ,
+ _GL_ARB_vertex_shader ,
+ _GL_ARB_fragment_shader ,
+ _GL_ARB_shading_language_100 ,
+ _GL_ARB_texture_non_power_of_two ,
+ _GL_ARB_point_sprite ,
+ _GL_ARB_fragment_program_shadow ,
+
+ /* Non ARB Extensions */
+ _GL_EXT_abgr ,
+ _GL_EXT_blend_color ,
+ _GL_EXT_polygon_offset ,
+ _GL_EXT_texture ,
+ _GL_EXT_texture3D ,
+ _GL_SGIS_texture_filter4 ,
+ _GL_EXT_subtexture ,
+ _GL_EXT_copy_texture ,
+ _GL_EXT_histogram ,
+ _GL_EXT_convolution ,
+ _GL_SGI_color_matrix ,
+ _GL_SGI_color_table ,
+ _GL_SGIS_pixel_texture ,
+ _GL_SGIS_texture4D ,
+ _GL_SGI_texture_color_table ,
+ _GL_EXT_cmyka ,
+ _GL_EXT_texture_object ,
+ _GL_SGIS_detail_texture ,
+ _GL_SGIS_sharpen_texture ,
+ _GL_EXT_packed_pixels ,
+ _GL_SGIS_texture_lod ,
+ _GL_SGIS_multisample ,
+ _GL_EXT_rescale_normal ,
+ _GLX_EXT_visual_info ,
+ _GL_EXT_vertex_array ,
+ _GL_EXT_misc_attribute ,
+ _GL_SGIS_generate_mipmap ,
+ _GL_SGIX_clipmap ,
+ _GL_SGIX_shadow ,
+ _GL_SGIS_texture_edge_clamp ,
+ _GL_SGIS_texture_border_clamp ,
+ _GL_EXT_blend_minmax ,
+ _GL_EXT_blend_subtract ,
+ _GL_EXT_blend_logic_op ,
+ _GLX_SGI_swap_control ,
+ _GLX_SGI_video_sync ,
+ _GLX_SGI_make_current_read ,
+ _GLX_SGIX_video_source ,
+ _GLX_EXT_visual_rating ,
+ _GL_SGIX_interlace ,
+ _GLX_EXT_import_context ,
+ _GLX_SGIX_fbconfig ,
+ _GLX_SGIX_pbuffer ,
+ _GL_SGIS_texture_select ,
+ _GL_SGIX_sprite ,
+ _GL_SGIX_texture_multi_buffer ,
+ _GL_EXT_point_parameters ,
+ _GL_SGIX_instruments ,
+ _GL_SGIX_texture_scale_bias ,
+ _GL_SGIX_framezoom ,
+ _GL_SGIX_tag_sample_buffer ,
+ _GL_SGIX_reference_plane ,
+ _GL_SGIX_flush_raster ,
+ _GLX_SGI_cushion ,
+ _GL_SGIX_depth_texture ,
+ _GL_SGIS_fog_function ,
+ _GL_SGIX_fog_offset ,
+ _GL_HP_image_transform ,
+ _GL_HP_convolution_border_modes ,
+ _GL_SGIX_texture_add_env ,
+ _GL_EXT_color_subtable ,
+ _GLU_EXT_object_space_tess ,
+ _GL_PGI_vertex_hints ,
+ _GL_PGI_misc_hints ,
+ _GL_EXT_paletted_texture ,
+ _GL_EXT_clip_volume_hint ,
+ _GL_SGIX_list_priority ,
+ _GL_SGIX_ir_instrument1 ,
+ _GLX_SGIX_video_resize ,
+ _GL_SGIX_texture_lod_bias ,
+ _GLU_SGI_filter4_parameters ,
+ _GLX_SGIX_dm_buffer ,
+ _GL_SGIX_shadow_ambient ,
+ _GLX_SGIX_swap_group ,
+ _GLX_SGIX_swap_barrier ,
+ _GL_EXT_index_texture ,
+ _GL_EXT_index_material ,
+ _GL_EXT_index_func ,
+ _GL_EXT_index_array_formats ,
+ _GL_EXT_compiled_vertex_array ,
+ _GL_EXT_cull_vertex ,
+ _GLU_EXT_nurbs_tessellator ,
+ _GL_SGIX_ycrcb ,
+ _GL_EXT_fragment_lighting ,
+ _GL_IBM_rasterpos_clip ,
+ _GL_HP_texture_lighting ,
+ _GL_EXT_draw_range_elements ,
+ _GL_WIN_phong_shading ,
+ _GL_WIN_specular_fog ,
+ _GLX_SGIS_color_range ,
+ _GL_EXT_light_texture ,
+ _GL_SGIX_blend_alpha_minmax ,
+ _GL_EXT_scene_marker ,
+ _GL_SGIX_pixel_texture_bits ,
+ _GL_EXT_bgra ,
+ _GL_SGIX_async ,
+ _GL_SGIX_async_pixel ,
+ _GL_SGIX_async_histogram ,
+ _GL_INTEL_texture_scissor ,
+ _GL_INTEL_parallel_arrays ,
+ _GL_HP_occlusion_test ,
+ _GL_EXT_pixel_transform ,
+ _GL_EXT_pixel_transform_color_table ,
+ _GL_EXT_shared_texture_palette ,
+ _GLX_SGIS_blended_overlay ,
+ _GL_EXT_separate_specular_color ,
+ _GL_EXT_secondary_color ,
+ _GL_EXT_texture_env ,
+ _GL_EXT_texture_perturb_normal ,
+ _GL_EXT_multi_draw_arrays ,
+ _GL_EXT_fog_coord ,
+ _GL_REND_screen_coordinates ,
+ _GL_EXT_coordinate_frame ,
+ _GL_EXT_texture_env_combine ,
+ _GL_APPLE_specular_vector ,
+ _GL_SGIX_pixel_texture ,
+ _GL_APPLE_transform_hint ,
+ _GL_SUNX_constant_data ,
+ _GL_SUN_global_alpha ,
+ _GL_SUN_triangle_list ,
+ _GL_SUN_vertex ,
+ _WGL_EXT_display_color_table ,
+ _WGL_EXT_extensions_string ,
+ _WGL_EXT_make_current_read ,
+ _WGL_EXT_pixel_format ,
+ _WGL_EXT_pbuffer ,
+ _WGL_EXT_swap_control ,
+ _GL_EXT_blend_func_separate ,
+ _GL_INGR_color_clamp ,
+ _GL_INGR_interlace_read ,
+ _GL_EXT_stencil_wrap ,
+ _WGL_EXT_depth_float ,
+ _GL_EXT_422_pixels ,
+ _GL_NV_texgen_reflection ,
+ _GL_SGIX_texture_range ,
+ _GL_SUN_convolution_border_modes ,
+ _GLX_SUN_get_transparent_index ,
+ _GL_EXT_texture_env_add ,
+ _GL_EXT_texture_lod_bias ,
+ _GL_EXT_texture_filter_anisotropic ,
+ _GL_EXT_vertex_weighting ,
+ _GL_NV_light_max_exponent ,
+ _GL_NV_vertex_array_range ,
+ _GL_NV_register_combiners ,
+ _GL_NV_fog_distance ,
+ _GL_NV_texgen_emboss ,
+ _GL_NV_blend_square ,
+ _GL_NV_texture_env_combine4 ,
+ _GL_MESA_resize_buffers ,
+ _GL_MESA_window_pos ,
+ _GL_EXT_texture_compression_s3tc ,
+ _GL_IBM_cull_vertex ,
+ _GL_IBM_multimode_draw_arrays ,
+ _GL_IBM_vertex_array_lists ,
+ _GL_3DFX_texture_compression_FXT1 ,
+ _GL_3DFX_multisample ,
+ _GL_3DFX_tbuffer ,
+ _WGL_EXT_multisample ,
+ _GL_SGIX_vertex_preclip ,
+ _GL_SGIX_resample ,
+ _GL_SGIS_texture_color_mask ,
+ _GLX_MESA_copy_sub_buffer ,
+ _GLX_MESA_pixmap_colormap ,
+ _GLX_MESA_release_buffers ,
+ _GLX_MESA_set_3dfx_mode ,
+ _GL_EXT_texture_env_dot3 ,
+ _GL_ATI_texture_mirror_once ,
+ _GL_NV_fence ,
+ _GL_IBM_static_data ,
+ _GL_IBM_texture_mirrored_repeat ,
+ _GL_NV_evaluators ,
+ _GL_NV_packed_depth_stencil ,
+ _GL_NV_register_combiners2 ,
+ _GL_NV_texture_compression_vtc ,
+ _GL_NV_texture_rectangle ,
+ _GL_NV_texture_shader ,
+ _GL_NV_texture_shader2 ,
+ _GL_NV_vertex_array_range2 ,
+ _GL_NV_vertex_program ,
+ _GLX_SGIX_visual_select_group ,
+ _GL_SGIX_texture_coordinate_clamp ,
+ _GLX_OML_swap_method ,
+ _GLX_OML_sync_control ,
+ _GL_OML_interlace ,
+ _GL_OML_subsample ,
+ _GL_OML_resample ,
+ _WGL_OML_sync_control ,
+ _GL_NV_copy_depth_to_color ,
+ _GL_ATI_envmap_bumpmap ,
+ _GL_ATI_fragment_shader ,
+ _GL_ATI_pn_triangles ,
+ _GL_ATI_vertex_array_object ,
+ _GL_EXT_vertex_shader ,
+ _GL_ATI_vertex_streams ,
+ _WGL_I3D_digital_video_control ,
+ _WGL_I3D_gamma ,
+ _WGL_I3D_genlock ,
+ _WGL_I3D_image_buffer ,
+ _WGL_I3D_swap_frame_lock ,
+ _WGL_I3D_swap_frame_usage ,
+ _GL_ATI_element_array ,
+ _GL_SUN_mesh_array ,
+ _GL_SUN_slice_accum ,
+ _GL_NV_multisample_filter_hint ,
+ _GL_NV_depth_clamp ,
+ _GL_NV_occlusion_query ,
+ _GL_NV_point_sprite ,
+ _WGL_NV_render_depth_texture ,
+ _WGL_NV_render_texture_rectangle ,
+ _GL_NV_texture_shader3 ,
+ _GL_NV_vertex_program1_1 ,
+ _GL_EXT_shadow_funcs ,
+ _GL_EXT_stencil_two_side ,
+ _GL_ATI_text_fragment_shader ,
+ _GL_APPLE_client_storage ,
+ _GL_APPLE_element_array ,
+ _GL_APPLE_fence ,
+ _GL_APPLE_vertex_array_object ,
+ _GL_APPLE_vertex_array_range ,
+ _GL_APPLE_ycbcr_422 ,
+ _GL_S3_s3tc ,
+ _GL_ATI_draw_buffers ,
+ _WGL_ATI_pixel_format_float ,
+ _GL_ATI_texture_env_combine3 ,
+ _GL_ATI_texture_float ,
+ _GL_NV_float_buffer ,
+ _GL_NV_fragment_program ,
+ _GL_NV_half_float ,
+ _GL_NV_pixel_data_range ,
+ _GL_NV_primitive_restart ,
+ _GL_NV_texture_expand_normal ,
+ _GL_NV_vertex_program2 ,
+ _GL_ATI_map_object_buffer ,
+ _GL_ATI_separate_stencil ,
+ _GL_ATI_vertex_attrib_array_object ,
+ _GL_OES_byte_coordinates ,
+ _GL_OES_fixed_point ,
+ _GL_OES_single_precision ,
+ _GL_OES_compressed_paletted_texture ,
+ _GL_OES_read_format ,
+ _GL_OES_query_matrix ,
+ _GL_EXT_depth_bounds_test ,
+ _GL_EXT_texture_mirror_clamp ,
+ _GL_EXT_blend_equation_separate ,
+ _GL_MESA_pack_invert ,
+ _GL_MESA_ycbcr_texture,
+
+ /* Finished */
+ _BGL_TEST,
+ NUM_EXTENSIONS
+ } ExtensionName;
+
+ /**
+ * Checks at runtime whether OpenGL supports the named extension.
+ * Returns true if OpenGL supports the given extension.
+ *
+ * @param name The extension name to check.
+ */
+ bool QueryExtension(ExtensionName name);
+ /**
+ * Checks the OpenGL version.
+ * Returns true if OpenGL is at least the given version.
+ *
+ * @param major The major version required
+ * @param minor The minor version required
+ */
+ bool QueryVersion(int major, int minor);
+ /**
+ * This will dynamically link all runtime supported extensions into
+ * the binary.
+ *
+ * @param debug Enable debug printing. This will print debugging info
+ * when extensions are loaded.
+ */
+ void InitExtensions(int debug);
+
+#if defined(PFNGLPNTRIANGLESIATIPROC)
+extern PFNGLPNTRIANGLESIATIPROC blPNTrianglesiATI;
+extern PFNGLPNTRIANGLESFATIPROC blPNTrianglesfATI;
+#endif
+
+
+// quick runtime checks
+typedef struct BL_EXTInfo
+{
+ BL_EXTInfo():
+ _ARB_multitexture(0),
+ _ARB_texture_env_combine(0),
+ _EXT_blend_color(0),
+ _ARB_texture_cube_map(0),
+ _ARB_shader_objects(0),
+ _ARB_vertex_shader(0),
+ _ARB_fragment_shader(0),
+ _EXT_texture3D(0),
+ _ARB_vertex_program(0),
+ _ARB_depth_texture(0),
+ _EXT_compiled_vertex_array(0)
+ {
+ //
+ }
+ bool _ARB_multitexture;
+ bool _ARB_texture_env_combine;
+ bool _EXT_blend_color;
+ bool _ARB_texture_cube_map;
+ bool _ARB_shader_objects;
+ bool _ARB_vertex_shader;
+ bool _ARB_fragment_shader;
+ bool _EXT_texture3D;
+ bool _ARB_vertex_program;
+ bool _ARB_depth_texture;
+ bool _EXT_compiled_vertex_array;
+}BL_EXTInfo;
+
+extern BL_EXTInfo RAS_EXT_support;
+
+#ifdef GL_ARB_multitexture // defined in glext.h now...
+extern int max_texture_units;
+extern PFNGLACTIVETEXTUREARBPROC blActiveTextureARB;
+extern PFNGLCLIENTACTIVETEXTUREARBPROC blClientActiveTextureARB;
+extern PFNGLMULTITEXCOORD1DARBPROC blMultiTexCoord1dARB;
+extern PFNGLMULTITEXCOORD1DVARBPROC blMultiTexCoord1dvARB;
+extern PFNGLMULTITEXCOORD1FARBPROC blMultiTexCoord1fARB;
+extern PFNGLMULTITEXCOORD1FVARBPROC blMultiTexCoord1fvARB;
+extern PFNGLMULTITEXCOORD1IARBPROC blMultiTexCoord1iARB;
+extern PFNGLMULTITEXCOORD1IVARBPROC blMultiTexCoord1ivARB;
+extern PFNGLMULTITEXCOORD1SARBPROC blMultiTexCoord1sARB;
+extern PFNGLMULTITEXCOORD1SVARBPROC blMultiTexCoord1svARB;
+extern PFNGLMULTITEXCOORD2DARBPROC blMultiTexCoord2dARB;
+extern PFNGLMULTITEXCOORD2DVARBPROC blMultiTexCoord2dvARB;
+extern PFNGLMULTITEXCOORD2FARBPROC blMultiTexCoord2fARB;
+extern PFNGLMULTITEXCOORD2FVARBPROC blMultiTexCoord2fvARB;
+extern PFNGLMULTITEXCOORD2IARBPROC blMultiTexCoord2iARB;
+extern PFNGLMULTITEXCOORD2IVARBPROC blMultiTexCoord2ivARB;
+extern PFNGLMULTITEXCOORD2SARBPROC blMultiTexCoord2sARB;
+extern PFNGLMULTITEXCOORD2SVARBPROC blMultiTexCoord2svARB;
+extern PFNGLMULTITEXCOORD3DARBPROC blMultiTexCoord3dARB;
+extern PFNGLMULTITEXCOORD3DVARBPROC blMultiTexCoord3dvARB;
+extern PFNGLMULTITEXCOORD3FARBPROC blMultiTexCoord3fARB;
+extern PFNGLMULTITEXCOORD3FVARBPROC blMultiTexCoord3fvARB;
+extern PFNGLMULTITEXCOORD3IARBPROC blMultiTexCoord3iARB;
+extern PFNGLMULTITEXCOORD3IVARBPROC blMultiTexCoord3ivARB;
+extern PFNGLMULTITEXCOORD3SARBPROC blMultiTexCoord3sARB;
+extern PFNGLMULTITEXCOORD3SVARBPROC blMultiTexCoord3svARB;
+extern PFNGLMULTITEXCOORD4DARBPROC blMultiTexCoord4dARB;
+extern PFNGLMULTITEXCOORD4DVARBPROC blMultiTexCoord4dvARB;
+extern PFNGLMULTITEXCOORD4FARBPROC blMultiTexCoord4fARB;
+extern PFNGLMULTITEXCOORD4FVARBPROC blMultiTexCoord4fvARB;
+extern PFNGLMULTITEXCOORD4IARBPROC blMultiTexCoord4iARB;
+extern PFNGLMULTITEXCOORD4IVARBPROC blMultiTexCoord4ivARB;
+extern PFNGLMULTITEXCOORD4SARBPROC blMultiTexCoord4sARB;
+extern PFNGLMULTITEXCOORD4SVARBPROC blMultiTexCoord4svARB;
+#endif
+
+
+#ifdef GL_ARB_shader_objects
+extern PFNGLDELETEOBJECTARBPROC blDeleteObjectARB;
+extern PFNGLGETHANDLEARBPROC blGetHandleARB;
+extern PFNGLDETACHOBJECTARBPROC blDetachObjectARB;
+extern PFNGLCREATESHADEROBJECTARBPROC blCreateShaderObjectARB;
+extern PFNGLSHADERSOURCEARBPROC blShaderSourceARB;
+extern PFNGLCOMPILESHADERARBPROC blCompileShaderARB;
+extern PFNGLCREATEPROGRAMOBJECTARBPROC blCreateProgramObjectARB;
+extern PFNGLATTACHOBJECTARBPROC blAttachObjectARB;
+extern PFNGLLINKPROGRAMARBPROC blLinkProgramARB;
+extern PFNGLUSEPROGRAMOBJECTARBPROC blUseProgramObjectARB;
+extern PFNGLVALIDATEPROGRAMARBPROC blValidateProgramARB;
+extern PFNGLUNIFORM1FARBPROC blUniform1fARB;
+extern PFNGLUNIFORM2FARBPROC blUniform2fARB;
+extern PFNGLUNIFORM3FARBPROC blUniform3fARB;
+extern PFNGLUNIFORM4FARBPROC blUniform4fARB;
+extern PFNGLUNIFORM1IARBPROC blUniform1iARB;
+extern PFNGLUNIFORM2IARBPROC blUniform2iARB;
+extern PFNGLUNIFORM3IARBPROC blUniform3iARB;
+extern PFNGLUNIFORM4IARBPROC blUniform4iARB;
+extern PFNGLUNIFORM1FVARBPROC blUniform1fvARB;
+extern PFNGLUNIFORM2FVARBPROC blUniform2fvARB;
+extern PFNGLUNIFORM3FVARBPROC blUniform3fvARB;
+extern PFNGLUNIFORM4FVARBPROC blUniform4fvARB;
+extern PFNGLUNIFORM1IVARBPROC blUniform1ivARB;
+extern PFNGLUNIFORM2IVARBPROC blUniform2ivARB;
+extern PFNGLUNIFORM3IVARBPROC blUniform3ivARB;
+extern PFNGLUNIFORM4IVARBPROC blUniform4ivARB;
+extern PFNGLUNIFORMMATRIX2FVARBPROC blUniformMatrix2fvARB;
+extern PFNGLUNIFORMMATRIX3FVARBPROC blUniformMatrix3fvARB;
+extern PFNGLUNIFORMMATRIX4FVARBPROC blUniformMatrix4fvARB;
+extern PFNGLGETOBJECTPARAMETERFVARBPROC blGetObjectParameterfvARB;
+extern PFNGLGETOBJECTPARAMETERIVARBPROC blGetObjectParameterivARB;
+extern PFNGLGETINFOLOGARBPROC blGetInfoLogARB;
+extern PFNGLGETATTACHEDOBJECTSARBPROC blGetAttachedObjectsARB;
+extern PFNGLGETUNIFORMLOCATIONARBPROC blGetUniformLocationARB;
+extern PFNGLGETACTIVEUNIFORMARBPROC blGetActiveUniformARB;
+extern PFNGLGETUNIFORMFVARBPROC blGetUniformfvARB;
+extern PFNGLGETUNIFORMIVARBPROC blGetUniformivARB;
+extern PFNGLGETSHADERSOURCEARBPROC blGetShaderSourceARB;
+#endif
+
+#ifdef GL_ARB_vertex_shader
+extern PFNGLBINDATTRIBLOCATIONARBPROC blBindAttribLocationARB;
+extern PFNGLGETACTIVEATTRIBARBPROC blGetActiveAttribARB;
+extern PFNGLGETATTRIBLOCATIONARBPROC blGetAttribLocationARB;
+#endif
+
+#ifdef GL_ARB_vertex_program
+extern PFNGLVERTEXATTRIB1FARBPROC blVertexAttrib1fARB;
+extern PFNGLVERTEXATTRIB1FVARBPROC blVertexAttrib1fvARB;
+extern PFNGLVERTEXATTRIB2FARBPROC blVertexAttrib2fARB;
+extern PFNGLVERTEXATTRIB2FVARBPROC blVertexAttrib2fvARB;
+extern PFNGLVERTEXATTRIB3FARBPROC blVertexAttrib3fARB;
+extern PFNGLVERTEXATTRIB3FVARBPROC blVertexAttrib3fvARB;
+extern PFNGLVERTEXATTRIB4FARBPROC blVertexAttrib4fARB;
+extern PFNGLVERTEXATTRIB4FVARBPROC blVertexAttrib4fvARB;
+extern PFNGLGETPROGRAMSTRINGARBPROC blGetProgramStringARB;
+extern PFNGLGETVERTEXATTRIBDVARBPROC blGetVertexAttribdvARB;
+extern PFNGLGETVERTEXATTRIBFVARBPROC blGetVertexAttribfvARB;
+extern PFNGLGETVERTEXATTRIBIVARBPROC blGetVertexAttribivARB;
+#endif
+
+/*
+#ifdef GL_EXT_compiled_vertex_array
+extern PFNGLLOCKARRAYSEXTPROC blLockArraysEXT;
+extern PFNGLUNLOCKARRAYSEXTPROC blUnlockArraysEXT;
+#endif
+*/
+} /* namespace bgl */
+
+
+#endif /* __RAS_GLEXTENSIONMANAGER_H__ */
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
new file mode 100644
index 00000000000..ed4cfb2ae42
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
@@ -0,0 +1,210 @@
+//
+#include <iostream>
+
+#include "RAS_ListRasterizer.h"
+
+#ifdef WIN32
+#include <windows.h>
+#endif // WIN32
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#else
+#include <GL/gl.h>
+#endif
+
+#include "RAS_TexVert.h"
+#include "RAS_GLExtensionManager.h"
+#include "MT_assert.h"
+
+//#ifndef NDEBUG
+//#ifdef WIN32
+//#define spit(x) std::cout << x << std::endl;
+//#endif //WIN32
+//#else
+#define spit(x)
+//#endif
+
+RAS_ListSlot::RAS_ListSlot()
+: KX_ListSlot(),
+ m_flag(LIST_MODIFY|LIST_CREATE),
+ m_list(0)
+{
+}
+
+RAS_ListSlot::~RAS_ListSlot()
+{
+ RemoveList();
+}
+
+
+void RAS_ListSlot::RemoveList()
+{
+ if(m_list != 0) {
+ spit("Releasing display list (" << m_list << ")");
+ glDeleteLists((GLuint)m_list, 1);
+ m_list =0;
+ }
+}
+
+void RAS_ListSlot::DrawList()
+{
+ if(m_flag &LIST_STREAM || m_flag& LIST_NOCREATE) {
+ RemoveList();
+ return;
+ }
+ if(m_flag &LIST_MODIFY) {
+ if(m_flag &LIST_CREATE) {
+ if(m_list == 0) {
+ m_list = (unsigned int)glGenLists(1);
+ m_flag = m_flag &~ LIST_CREATE;
+ spit("Created display list (" << m_list << ")");
+ }
+ }
+ if(m_list != 0)
+ glNewList((GLuint)m_list, GL_COMPILE);
+
+ m_flag |= LIST_BEGIN;
+ return;
+ }
+ glCallList(m_list);
+}
+
+void RAS_ListSlot::EndList()
+{
+ if(m_flag & LIST_BEGIN) {
+ glEndList();
+ m_flag = m_flag &~(LIST_BEGIN|LIST_MODIFY);
+ m_flag |= LIST_END;
+ glCallList(m_list);
+ }
+}
+
+void RAS_ListSlot::SetModified(bool mod)
+{
+ if(mod && !(m_flag & LIST_MODIFY)) {
+ spit("Modifying list (" << m_list << ")");
+ m_flag = m_flag &~ LIST_END;
+ m_flag |= LIST_STREAM;
+ }
+}
+
+bool RAS_ListSlot::End()
+{
+ return (m_flag &LIST_END)!=0;
+}
+
+
+
+RAS_ListRasterizer::RAS_ListRasterizer(RAS_ICanvas* canvas)
+: RAS_OpenGLRasterizer(canvas)
+{
+ // --
+}
+
+RAS_ListRasterizer::~RAS_ListRasterizer()
+{
+ ReleaseAlloc();
+}
+
+RAS_ListSlot* RAS_ListRasterizer::FindOrAdd(const vecVertexArray& vertexarrays, KX_ListSlot** slot)
+{
+ /*
+ Keep a copy of constant lists submitted for rendering,
+ this guards against (replicated)new...delete every frame,
+ and we can reuse lists!
+ :: sorted by vertex array
+ */
+ RAS_ListSlot* localSlot = (RAS_ListSlot*)*slot;
+ if(!localSlot) {
+ RAS_Lists::iterator it = mLists.find(vertexarrays);
+ if(it == mLists.end()) {
+ localSlot = new RAS_ListSlot();
+ mLists.insert(std::pair<vecVertexArray, RAS_ListSlot*>(vertexarrays, localSlot));
+ } else {
+ localSlot = it->second;
+ }
+ }
+ MT_assert(localSlot);
+ return localSlot;
+}
+
+void RAS_ListRasterizer::ReleaseAlloc()
+{
+ RAS_Lists::iterator it = mLists.begin();
+ while(it != mLists.end()) {
+ delete it->second;
+ it++;
+ }
+ mLists.clear();
+}
+
+
+void RAS_ListRasterizer::IndexPrimitives(
+ const vecVertexArray & vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot)
+{
+ RAS_ListSlot* localSlot =0;
+
+ // useObjectColor(are we updating every frame?)
+ if(!useObjectColor) {
+ localSlot = FindOrAdd(vertexarrays, slot);
+ localSlot->DrawList();
+ if(localSlot->End())
+ return;
+ }
+
+ RAS_OpenGLRasterizer::IndexPrimitives(
+ vertexarrays, indexarrays,
+ mode, polymat,
+ rendertools, useObjectColor,
+ rgbacolor,slot
+ );
+
+ if(!useObjectColor) {
+ localSlot->EndList();
+ *slot = localSlot;
+ }
+}
+
+
+void RAS_ListRasterizer::IndexPrimitivesMulti(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot)
+{
+ RAS_ListSlot* localSlot =0;
+
+ // useObjectColor(are we updating every frame?)
+ if(!useObjectColor) {
+ localSlot = FindOrAdd(vertexarrays, slot);
+ localSlot->DrawList();
+
+ if(localSlot->End())
+ return;
+ }
+
+ RAS_OpenGLRasterizer::IndexPrimitivesMulti(
+ vertexarrays, indexarrays,
+ mode, polymat,
+ rendertools, useObjectColor,
+ rgbacolor,slot
+ );
+ if(!useObjectColor) {
+ localSlot->EndList();
+ *slot = localSlot;
+ }
+}
+
+// eof
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h
new file mode 100644
index 00000000000..82840cd1399
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h
@@ -0,0 +1,72 @@
+#ifndef __RAS_LISTRASTERIZER_H__
+#define __RAS_LISTRASTERIZER_H__
+
+#include "RAS_MaterialBucket.h"
+#include "RAS_OpenGLRasterizer.h"
+#include <vector>
+
+class RAS_ListSlot : public KX_ListSlot
+{
+ unsigned int m_list;
+ unsigned int m_flag;
+public:
+ RAS_ListSlot();
+ virtual ~RAS_ListSlot();
+ virtual void SetModified(bool mod);
+
+ void RemoveList();
+ void DrawList();
+ void EndList();
+ bool End();
+
+};
+
+enum RAS_ListSlotFlags {
+ LIST_CREATE =1,
+ LIST_MODIFY =2,
+ LIST_STREAM =4,
+ LIST_NOCREATE =8,
+ LIST_BEGIN =16,
+ LIST_END =32,
+ LIST_REGEN =64
+};
+
+typedef std::map<const vecVertexArray, RAS_ListSlot*> RAS_Lists;
+
+class RAS_ListRasterizer : public RAS_OpenGLRasterizer
+{
+ RAS_Lists mLists;
+
+ RAS_ListSlot* FindOrAdd(const vecVertexArray& vertexarrays, KX_ListSlot** slot);
+ void ReleaseAlloc();
+
+public:
+ RAS_ListRasterizer(RAS_ICanvas* canvas);
+ virtual ~RAS_ListRasterizer();
+
+ virtual void IndexPrimitives(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot
+ );
+
+ virtual void IndexPrimitivesMulti(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot
+ );
+
+ virtual bool QueryLists(){return true;}
+};
+
+#endif
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
new file mode 100644
index 00000000000..85250fcd552
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
@@ -0,0 +1,1995 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "RAS_OpenGLRasterizer.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+#endif // WIN32
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif
+
+#include "RAS_Rect.h"
+#include "RAS_TexVert.h"
+#include "MT_CmMatrix4x4.h"
+#include "RAS_IRenderTools.h" // rendering text
+
+#include "RAS_GLExtensionManager.h"
+
+/**
+ * 32x32 bit masks for vinterlace stereo mode
+ */
+static GLuint left_eye_vinterlace_mask[32];
+static GLuint right_eye_vinterlace_mask[32];
+
+/**
+ * 32x32 bit masks for hinterlace stereo mode.
+ * Left eye = &hinterlace_mask[0]
+ * Right eye = &hinterlace_mask[1]
+ */
+static GLuint hinterlace_mask[33];
+
+RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas)
+ :RAS_IRasterizer(canvas),
+ m_2DCanvas(canvas),
+ m_fogenabled(false),
+ m_time(0.0),
+ m_stereomode(RAS_STEREO_NOSTEREO),
+ m_curreye(RAS_STEREO_LEFTEYE),
+ m_eyeseparation(0.0),
+ m_seteyesep(false),
+ m_focallength(0.0),
+ m_setfocallength(false),
+ m_noOfScanlines(32),
+ m_useTang(false),
+ m_materialCachingInfo(0),
+ m_motionblur(0),
+ m_motionblurvalue(-1.0)
+{
+ m_viewmatrix.Identity();
+
+ for (int i = 0; i < 32; i++)
+ {
+ left_eye_vinterlace_mask[i] = 0x55555555;
+ right_eye_vinterlace_mask[i] = 0xAAAAAAAA;
+ hinterlace_mask[i] = (i&1)*0xFFFFFFFF;
+ }
+ hinterlace_mask[32] = 0;
+}
+
+
+
+RAS_OpenGLRasterizer::~RAS_OpenGLRasterizer()
+{
+}
+
+
+
+static void Myinit_gl_stuff(void)
+{
+ float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 };
+ float mat_shininess[] = { 35.0 };
+/* float one= 1.0; */
+ int a, x, y;
+ GLubyte pat[32*32];
+ const GLubyte *patc= pat;
+
+ 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);
+
+
+#if defined(__FreeBSD) || defined(__linux__)
+ glDisable(GL_DITHER); /* op sgi/sun hardware && 12 bits */
+#endif
+
+ /* 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);
+
+ 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);
+
+ 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);
+
+ glFrontFace(GL_CCW);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+}
+
+
+
+bool RAS_OpenGLRasterizer::Init()
+{
+
+ Myinit_gl_stuff();
+
+ m_redback = 0.4375;
+ m_greenback = 0.4375;
+ m_blueback = 0.4375;
+ m_alphaback = 0.0;
+
+ m_ambr = 0.0f;
+ m_ambg = 0.0f;
+ m_ambb = 0.0f;
+
+ glClearColor(m_redback,m_greenback,m_blueback,m_alphaback);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glShadeModel(GL_SMOOTH);
+
+ return true;
+}
+
+
+void RAS_OpenGLRasterizer::SetAmbientColor(float red, float green, float blue)
+{
+ m_ambr = red;
+ m_ambg = green;
+ m_ambb = blue;
+}
+
+
+void RAS_OpenGLRasterizer::SetAlphaTest(bool enable)
+{
+ if (enable)
+ {
+ glEnable(GL_ALPHA_TEST);
+ glAlphaFunc(GL_GREATER, 0.6f);
+ }
+ else glDisable(GL_ALPHA_TEST);
+}
+
+
+
+void RAS_OpenGLRasterizer::SetAmbient(float factor)
+{
+ float ambient[] = { m_ambr*factor, m_ambg*factor, m_ambb*factor, 1.0f };
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
+}
+
+
+void RAS_OpenGLRasterizer::SetBackColor(float red,
+ float green,
+ float blue,
+ float alpha)
+{
+ m_redback = red;
+ m_greenback = green;
+ m_blueback = blue;
+ m_alphaback = alpha;
+}
+
+
+
+void RAS_OpenGLRasterizer::SetFogColor(float r,
+ float g,
+ float b)
+{
+ m_fogr = r;
+ m_fogg = g;
+ m_fogb = b;
+ m_fogenabled = true;
+}
+
+
+
+void RAS_OpenGLRasterizer::SetFogStart(float start)
+{
+ m_fogstart = start;
+ m_fogenabled = true;
+}
+
+
+
+void RAS_OpenGLRasterizer::SetFogEnd(float fogend)
+{
+ m_fogdist = fogend;
+ m_fogenabled = true;
+}
+
+
+
+void RAS_OpenGLRasterizer::SetFog(float start,
+ float dist,
+ float r,
+ float g,
+ float b)
+{
+ m_fogstart = start;
+ m_fogdist = dist;
+ m_fogr = r;
+ m_fogg = g;
+ m_fogb = b;
+ m_fogenabled = true;
+}
+
+
+
+void RAS_OpenGLRasterizer::DisableFog()
+{
+ m_fogenabled = false;
+}
+
+
+
+void RAS_OpenGLRasterizer::DisplayFog()
+{
+ if ((m_drawingmode >= KX_SOLID) && m_fogenabled)
+ {
+ float params[5];
+ glFogi(GL_FOG_MODE, GL_LINEAR);
+ glFogf(GL_FOG_DENSITY, 0.1f);
+ glFogf(GL_FOG_START, m_fogstart);
+ glFogf(GL_FOG_END, m_fogstart + m_fogdist);
+ params[0]= m_fogr;
+ params[1]= m_fogg;
+ params[2]= m_fogb;
+ params[3]= 0.0;
+ glFogfv(GL_FOG_COLOR, params);
+ glEnable(GL_FOG);
+ }
+ else
+ {
+ glDisable(GL_FOG);
+ }
+}
+
+
+
+bool RAS_OpenGLRasterizer::SetMaterial(const RAS_IPolyMaterial& mat)
+{
+ return mat.Activate(this, m_materialCachingInfo);
+}
+
+
+
+void RAS_OpenGLRasterizer::Exit()
+{
+
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST);
+ glClearDepth(1.0);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClearColor(m_redback, m_greenback, m_blueback, m_alphaback);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glDepthMask (GL_TRUE);
+ glDepthFunc(GL_LEQUAL);
+ glBlendFunc(GL_ONE, GL_ZERO);
+
+ glDisable(GL_POLYGON_STIPPLE);
+
+ glDisable(GL_LIGHTING);
+ if (bgl::QueryExtension(bgl::_GL_EXT_separate_specular_color) || bgl::QueryVersion(1, 2))
+ glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
+
+ EndFrame();
+}
+
+bool RAS_OpenGLRasterizer::InterlacedStereo() const
+{
+ return m_stereomode == RAS_STEREO_VINTERLACE || m_stereomode == RAS_STEREO_INTERLACED;
+}
+
+bool RAS_OpenGLRasterizer::BeginFrame(int drawingmode, double time)
+{
+ m_time = time;
+ m_drawingmode = drawingmode;
+
+ if (!InterlacedStereo() || m_curreye == RAS_STEREO_LEFTEYE)
+ {
+ m_2DCanvas->ClearColor(m_redback,m_greenback,m_blueback,m_alphaback);
+ m_2DCanvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER);
+ }
+
+ // Blender camera routine destroys the settings
+ if (m_drawingmode < KX_SOLID)
+ {
+ glDisable (GL_CULL_FACE);
+ glDisable (GL_DEPTH_TEST);
+ }
+ else
+ {
+ glEnable(GL_DEPTH_TEST);
+ glEnable (GL_CULL_FACE);
+ }
+
+ glShadeModel(GL_SMOOTH);
+
+ m_2DCanvas->BeginFrame();
+
+ return true;
+}
+
+
+
+void RAS_OpenGLRasterizer::SetDrawingMode(int drawingmode)
+{
+ m_drawingmode = drawingmode;
+
+ switch (m_drawingmode)
+ {
+ case KX_BOUNDINGBOX:
+ {
+ }
+ case KX_WIREFRAME:
+ {
+ glDisable (GL_CULL_FACE);
+ break;
+ }
+ case KX_TEXTURED:
+ {
+ }
+ case KX_SHADED:
+ {
+ }
+ case KX_SOLID:
+ {
+ }
+ default:
+ {
+ }
+ }
+}
+
+
+
+int RAS_OpenGLRasterizer::GetDrawingMode()
+{
+ return m_drawingmode;
+}
+
+
+
+void RAS_OpenGLRasterizer::SetDepthMask(DepthMask depthmask)
+{
+ glDepthMask(depthmask == KX_DEPTHMASK_DISABLED ? GL_FALSE : GL_TRUE);
+}
+
+
+
+void RAS_OpenGLRasterizer::ClearDepthBuffer()
+{
+ m_2DCanvas->ClearBuffer(RAS_ICanvas::DEPTH_BUFFER);
+}
+
+
+void RAS_OpenGLRasterizer::ClearCachingInfo(void)
+{
+ m_materialCachingInfo = 0;
+}
+
+
+void RAS_OpenGLRasterizer::EndFrame()
+{
+ glDisable(GL_LIGHTING);
+ glDisable(GL_TEXTURE_2D);
+
+ //DrawDebugLines
+ glBegin(GL_LINES);
+ for (unsigned int i=0;i<m_debugLines.size();i++)
+ {
+
+
+ glColor4f(m_debugLines[i].m_color[0],m_debugLines[i].m_color[1],m_debugLines[i].m_color[2],1.f);
+ const MT_Scalar* fromPtr = &m_debugLines[i].m_from.x();
+ const MT_Scalar* toPtr= &m_debugLines[i].m_to.x();
+
+ glVertex3dv(fromPtr);
+ glVertex3dv(toPtr);
+ }
+ glEnd();
+
+ m_debugLines.clear();
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ m_2DCanvas->EndFrame();
+}
+
+void RAS_OpenGLRasterizer::SetRenderArea()
+{
+ // only above/below stereo method needs viewport adjustment
+ switch (m_stereomode)
+ {
+ case RAS_STEREO_ABOVEBELOW:
+ switch(m_curreye)
+ {
+ case RAS_STEREO_LEFTEYE:
+ // upper half of window
+ m_2DCanvas->GetDisplayArea().SetLeft(0);
+ m_2DCanvas->GetDisplayArea().SetBottom(m_2DCanvas->GetHeight() -
+ int(m_2DCanvas->GetHeight() - m_noOfScanlines) / 2);
+
+ m_2DCanvas->GetDisplayArea().SetRight(int(m_2DCanvas->GetWidth()));
+ m_2DCanvas->GetDisplayArea().SetTop(int(m_2DCanvas->GetHeight()));
+ break;
+ case RAS_STEREO_RIGHTEYE:
+ // lower half of window
+ m_2DCanvas->GetDisplayArea().SetLeft(0);
+ m_2DCanvas->GetDisplayArea().SetBottom(0);
+ m_2DCanvas->GetDisplayArea().SetRight(int(m_2DCanvas->GetWidth()));
+ m_2DCanvas->GetDisplayArea().SetTop(int(m_2DCanvas->GetHeight() - m_noOfScanlines) / 2);
+ break;
+ }
+ break;
+ case RAS_STEREO_SIDEBYSIDE:
+ switch (m_curreye)
+ {
+ case RAS_STEREO_LEFTEYE:
+ // Left half of window
+ m_2DCanvas->GetDisplayArea().SetLeft(0);
+ m_2DCanvas->GetDisplayArea().SetBottom(0);
+ m_2DCanvas->GetDisplayArea().SetRight(m_2DCanvas->GetWidth()/2);
+ m_2DCanvas->GetDisplayArea().SetTop(m_2DCanvas->GetHeight());
+ break;
+ case RAS_STEREO_RIGHTEYE:
+ // Right half of window
+ m_2DCanvas->GetDisplayArea().SetLeft(m_2DCanvas->GetWidth()/2);
+ m_2DCanvas->GetDisplayArea().SetBottom(0);
+ m_2DCanvas->GetDisplayArea().SetRight(m_2DCanvas->GetWidth());
+ m_2DCanvas->GetDisplayArea().SetTop(m_2DCanvas->GetHeight());
+ break;
+ }
+ break;
+ default:
+ // every available pixel
+ m_2DCanvas->GetDisplayArea().SetLeft(0);
+ m_2DCanvas->GetDisplayArea().SetBottom(0);
+ m_2DCanvas->GetDisplayArea().SetRight(int(m_2DCanvas->GetWidth()));
+ m_2DCanvas->GetDisplayArea().SetTop(int(m_2DCanvas->GetHeight()));
+ break;
+ }
+}
+
+
+void RAS_OpenGLRasterizer::SetStereoMode(const StereoMode stereomode)
+{
+ m_stereomode = stereomode;
+}
+
+
+
+bool RAS_OpenGLRasterizer::Stereo()
+{
+ if(m_stereomode == RAS_STEREO_NOSTEREO)
+ return false;
+ else
+ return true;
+}
+
+
+void RAS_OpenGLRasterizer::SetEye(const StereoEye eye)
+{
+ m_curreye = eye;
+ switch (m_stereomode)
+ {
+ case RAS_STEREO_QUADBUFFERED:
+ glDrawBuffer(m_curreye == RAS_STEREO_LEFTEYE ? GL_BACK_LEFT : GL_BACK_RIGHT);
+ break;
+ case RAS_STEREO_ANAGLYPH:
+ if (m_curreye == RAS_STEREO_LEFTEYE)
+ {
+ glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_FALSE);
+ } else {
+ //glAccum(GL_LOAD, 1.0);
+ glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
+ ClearDepthBuffer();
+ }
+ break;
+ case RAS_STEREO_VINTERLACE:
+ {
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple((const GLubyte*) ((m_curreye == RAS_STEREO_LEFTEYE) ? left_eye_vinterlace_mask : right_eye_vinterlace_mask));
+ if (m_curreye == RAS_STEREO_RIGHTEYE)
+ ClearDepthBuffer();
+ break;
+ }
+ case RAS_STEREO_INTERLACED:
+ {
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple((const GLubyte*) &hinterlace_mask[m_curreye == RAS_STEREO_LEFTEYE?0:1]);
+ if (m_curreye == RAS_STEREO_RIGHTEYE)
+ ClearDepthBuffer();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+RAS_IRasterizer::StereoEye RAS_OpenGLRasterizer::GetEye()
+{
+ return m_curreye;
+}
+
+
+void RAS_OpenGLRasterizer::SetEyeSeparation(const float eyeseparation)
+{
+ m_eyeseparation = eyeseparation;
+ m_seteyesep = true;
+}
+
+float RAS_OpenGLRasterizer::GetEyeSeparation()
+{
+ return m_eyeseparation;
+}
+
+void RAS_OpenGLRasterizer::SetFocalLength(const float focallength)
+{
+ m_focallength = focallength;
+ m_setfocallength = true;
+}
+
+float RAS_OpenGLRasterizer::GetFocalLength()
+{
+ return m_focallength;
+}
+
+
+void RAS_OpenGLRasterizer::SwapBuffers()
+{
+ m_2DCanvas->SwapBuffers();
+}
+
+
+
+void RAS_OpenGLRasterizer::GetViewMatrix(MT_Matrix4x4 &mat) const
+{
+ float viewmat[16];
+ glGetFloatv(GL_MODELVIEW_MATRIX, viewmat);
+ mat.setValue(viewmat);
+}
+
+
+
+void RAS_OpenGLRasterizer::IndexPrimitives(const vecVertexArray & vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot
+ )
+{
+ GLenum drawmode;
+ switch (mode)
+ {
+ case 0:
+ drawmode = GL_TRIANGLES;
+ break;
+ case 1:
+ drawmode = GL_LINES;
+ break;
+ case 2:
+ drawmode = GL_QUADS;
+ break;
+ default:
+ drawmode = GL_LINES;
+ break;
+ }
+
+ const RAS_TexVert* vertexarray ;
+ unsigned int numindices,vt;
+
+ for (vt=0;vt<vertexarrays.size();vt++)
+ {
+ vertexarray = &((*vertexarrays[vt]) [0]);
+ const KX_IndexArray & indexarray = (*indexarrays[vt]);
+ numindices = indexarray.size();
+
+ if (!numindices)
+ break;
+
+ int vindex=0;
+ switch (mode)
+ {
+ case 1:
+ {
+ glBegin(GL_LINES);
+ vindex=0;
+ for (unsigned int i=0;i<numindices;i+=2)
+ {
+ glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ());
+ glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ());
+ }
+ glEnd();
+ }
+ break;
+ case 2:
+ {
+ glBegin(GL_QUADS);
+ vindex=0;
+ if (useObjectColor)
+ {
+ for (unsigned int i=0;i<numindices;i+=4)
+ {
+
+ glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]);
+
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ else
+ {
+ for (unsigned int i=0;i<numindices;i+=4)
+ {
+ // This looks curiously endian unsafe to me.
+ // However it depends on the way the colors are packed into
+ // the m_rgba field of RAS_TexVert
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ glEnd();
+ break;
+ }
+ case 0:
+ {
+ glBegin(GL_TRIANGLES);
+ vindex=0;
+ if (useObjectColor)
+ {
+ for (unsigned int i=0;i<numindices;i+=3)
+ {
+
+ glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]);
+
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ else
+ {
+ for (unsigned int i=0;i<numindices;i+=3)
+ {
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ glEnd();
+ break;
+ }
+ default:
+ {
+ }
+
+ } // switch
+ } // for each vertexarray
+
+}
+
+void RAS_OpenGLRasterizer::IndexPrimitives_Ex(const vecVertexArray & vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor
+ )
+{
+ bool recalc;
+ GLenum drawmode;
+ switch (mode)
+ {
+ case 0:
+ drawmode = GL_TRIANGLES;
+ break;
+ case 1:
+ drawmode = GL_LINES;
+ break;
+ case 2:
+ drawmode = GL_QUADS;
+ break;
+ default:
+ drawmode = GL_LINES;
+ break;
+ }
+
+ const RAS_TexVert* vertexarray ;
+ unsigned int numindices,vt;
+
+ for (vt=0;vt<vertexarrays.size();vt++)
+ {
+ vertexarray = &((*vertexarrays[vt]) [0]);
+ const KX_IndexArray & indexarray = (*indexarrays[vt]);
+ numindices = indexarray.size();
+
+ if (!numindices)
+ continue;
+
+ int vindex=0;
+ switch (mode)
+ {
+ case 1:
+ {
+ glBegin(GL_LINES);
+ vindex=0;
+ for (unsigned int i=0;i<numindices;i+=2)
+ {
+ glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ());
+ glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ());
+ }
+ glEnd();
+ }
+ break;
+ case 2:
+ {
+ glBegin(GL_QUADS);
+ vindex=0;
+ if (useObjectColor)
+ {
+ for (unsigned int i=0;i<numindices;i+=4)
+ {
+ MT_Point3 mv1, mv2, mv3, mv4, fnor;
+ /* Calc a new face normal */
+
+ if (vertexarray[(indexarray[vindex])].getFlag() & TV_CALCFACENORMAL)
+ recalc= true;
+ else
+ recalc=false;
+
+ if (recalc){
+ mv1 = MT_Point3(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ mv2 = MT_Point3(vertexarray[(indexarray[vindex+1])].getLocalXYZ());
+ mv3 = MT_Point3(vertexarray[(indexarray[vindex+2])].getLocalXYZ());
+ mv4 = MT_Point3(vertexarray[(indexarray[vindex+2])].getLocalXYZ());
+
+ fnor = (((mv2-mv1).cross(mv3-mv2))+((mv4-mv3).cross(mv1-mv4))).safe_normalized();
+
+ glNormal3f(fnor[0], fnor[1], fnor[2]);
+ }
+
+ glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]);
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ else
+ {
+ for (unsigned int i=0;i<numindices;i+=4)
+ {
+ // This looks curiously endian unsafe to me.
+ // However it depends on the way the colors are packed into
+ // the m_rgba field of RAS_TexVert
+ MT_Point3 mv1, mv2, mv3, mv4, fnor;
+ /* Calc a new face normal */
+
+ if (vertexarray[(indexarray[vindex])].getFlag() & TV_CALCFACENORMAL)
+ recalc= true;
+ else
+ recalc=false;
+
+
+ if (recalc){
+ mv1 = MT_Point3(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ mv2 = MT_Point3(vertexarray[(indexarray[vindex+1])].getLocalXYZ());
+ mv3 = MT_Point3(vertexarray[(indexarray[vindex+2])].getLocalXYZ());
+ mv4 = MT_Point3(vertexarray[(indexarray[vindex+3])].getLocalXYZ());
+
+ fnor = (((mv2-mv1).cross(mv3-mv2))+((mv4-mv3).cross(mv1-mv4))).safe_normalized();
+
+ glNormal3f(fnor[0], fnor[1], fnor[2]);
+ }
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ glEnd();
+ break;
+ }
+ case 0:
+ {
+ glBegin(GL_TRIANGLES);
+ vindex=0;
+ if (useObjectColor)
+ {
+ for (unsigned int i=0;i<numindices;i+=3)
+ {
+ MT_Point3 mv1, mv2, mv3, fnor;
+ /* Calc a new face normal */
+
+ if (vertexarray[(indexarray[vindex])].getFlag() & TV_CALCFACENORMAL)
+ recalc= true;
+ else
+ recalc=false;
+
+ if (recalc){
+ mv1 = MT_Point3(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ mv2 = MT_Point3(vertexarray[(indexarray[vindex+1])].getLocalXYZ());
+ mv3 = MT_Point3(vertexarray[(indexarray[vindex+2])].getLocalXYZ());
+
+ fnor = ((mv2-mv1).cross(mv3-mv2)).safe_normalized();
+ glNormal3f(fnor[0], fnor[1], fnor[2]);
+ }
+
+ glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]);
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ else
+ {
+ for (unsigned int i=0;i<numindices;i+=3)
+ {
+ MT_Point3 mv1, mv2, mv3, fnor;
+ /* Calc a new face normal */
+
+ if (vertexarray[(indexarray[vindex])].getFlag() & TV_CALCFACENORMAL)
+ recalc= true;
+ else
+ recalc=false;
+
+
+ if (recalc){
+ mv1 = MT_Point3(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ mv2 = MT_Point3(vertexarray[(indexarray[vindex+1])].getLocalXYZ());
+ mv3 = MT_Point3(vertexarray[(indexarray[vindex+2])].getLocalXYZ());
+
+ fnor = ((mv2-mv1).cross(mv3-mv2)).safe_normalized();
+ glNormal3f(fnor[0], fnor[1], fnor[2]);
+ }
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1());
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ glEnd();
+ break;
+ }
+ default:
+ {
+ }
+
+ } // switch
+ } // for each vertexarray
+
+}
+
+
+
+void RAS_OpenGLRasterizer::IndexPrimitives_3DText(const vecVertexArray & vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor
+ )
+{
+ GLenum drawmode;
+ switch (mode)
+ {
+ case 0:
+ drawmode = GL_TRIANGLES;
+ break;
+ case 1:
+ drawmode = GL_LINES;
+ break;
+ case 2:
+ drawmode = GL_QUADS;
+ break;
+ default:
+ drawmode = GL_LINES;
+ break;
+ }
+
+ const RAS_TexVert* vertexarray ;
+
+ unsigned int numindices, vt;
+
+ if (useObjectColor)
+ {
+ glDisableClientState(GL_COLOR_ARRAY);
+ glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]);
+ }
+ else
+ {
+ glEnableClientState(GL_COLOR_ARRAY);
+ }
+
+ for (vt=0;vt<vertexarrays.size();vt++)
+ {
+ vertexarray = &((*vertexarrays[vt]) [0]);
+ const KX_IndexArray & indexarray = (*indexarrays[vt]);
+ numindices = indexarray.size();
+
+ if (!numindices)
+ break;
+
+ int vindex=0;
+ switch (mode)
+ {
+ case 1:
+ {
+ glBegin(GL_LINES);
+ vindex=0;
+ for (unsigned int i=0;i<numindices;i+=2)
+ {
+ glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ());
+ glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ());
+ }
+ glEnd();
+ }
+ break;
+ case 2:
+ {
+ vindex=0;
+ for (unsigned int i=0;i<numindices;i+=4)
+ {
+ float v1[3],v2[3],v3[3],v4[3];
+
+ v1[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0];
+ v1[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1];
+ v1[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2];
+ vindex++;
+
+ v2[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0];
+ v2[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1];
+ v2[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2];
+ vindex++;
+
+ v3[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0];
+ v3[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1];
+ v3[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2];
+ vindex++;
+
+ v4[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0];
+ v4[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1];
+ v4[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2];
+
+ vindex++;
+
+ rendertools->RenderText(polymat->GetDrawingMode(),polymat,v1,v2,v3,v4);
+ ClearCachingInfo();
+ }
+ break;
+ }
+ case 0:
+ {
+ glBegin(GL_TRIANGLES);
+ vindex=0;
+ for (unsigned int i=0;i<numindices;i+=3)
+ {
+ float v1[3],v2[3],v3[3];
+
+ v1[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0];
+ v1[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1];
+ v1[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2];
+ vindex++;
+
+ v2[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0];
+ v2[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1];
+ v2[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2];
+ vindex++;
+
+ v3[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0];
+ v3[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1];
+ v3[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2];
+ vindex++;
+
+ rendertools->RenderText(polymat->GetDrawingMode(),polymat,v1,v2,v3,NULL);
+ ClearCachingInfo();
+ }
+ glEnd();
+ break;
+ }
+ default:
+ {
+ }
+ } //switch
+ } //for each vertexarray
+}
+
+void RAS_OpenGLRasterizer::SetTexCoords(TexCoGen coords,int unit)
+{
+ // this changes from material to material
+ if(unit < RAS_MAX)
+ m_texco[unit] = coords;
+}
+
+void RAS_OpenGLRasterizer::SetAttrib(int type)
+{
+ if(type == RAS_TEXTANGENT) m_useTang=true;
+}
+
+void RAS_OpenGLRasterizer::TexCoord(const RAS_TexVert &tv, int enabled)
+{
+#ifdef GL_ARB_multitexture
+ if(bgl::RAS_EXT_support._ARB_multitexture)
+ {
+ for(int unit=0; unit<enabled; unit++)
+ {
+ if( tv.getFlag() & TV_2NDUV && tv.getUnit() == unit ) {
+ bgl::blMultiTexCoord2fvARB(GL_TEXTURE0_ARB+unit, tv.getUV2());
+ continue;
+ }
+ switch(m_texco[unit])
+ {
+ case RAS_TEXCO_DISABLE:
+ case RAS_TEXCO_OBJECT:
+ case RAS_TEXCO_GEN:
+ break;
+ case RAS_TEXCO_ORCO:
+ case RAS_TEXCO_GLOB:
+ bgl::blMultiTexCoord3fvARB(GL_TEXTURE0_ARB+unit, tv.getLocalXYZ());
+ break;
+ case RAS_TEXCO_UV1:
+ bgl::blMultiTexCoord2fvARB(GL_TEXTURE0_ARB+unit, tv.getUV1());
+ break;
+ case RAS_TEXCO_NORM:
+ bgl::blMultiTexCoord3fvARB(GL_TEXTURE0_ARB+unit, tv.getNormal());
+ break;
+ case RAS_TEXTANGENT:
+ bgl::blMultiTexCoord4fvARB(GL_TEXTURE0_ARB+unit, tv.getTangent());
+ break;
+ case RAS_TEXCO_UV2:
+ bgl::blMultiTexCoord2fvARB(GL_TEXTURE0_ARB+unit, tv.getUV2());
+ break;
+ }
+ }
+ }
+#endif
+
+#ifdef GL_ARB_vertex_program
+ if(m_useTang && bgl::RAS_EXT_support._ARB_vertex_program)
+ bgl::blVertexAttrib4fvARB(1/*tangent*/, tv.getTangent());
+#endif
+
+}
+void RAS_OpenGLRasterizer::Tangent( const RAS_TexVert& v1,
+ const RAS_TexVert& v2,
+ const RAS_TexVert& v3,
+ const MT_Vector3 &no)
+{
+#ifdef GL_ARB_multitexture
+ // TODO: set for deformer...
+ MT_Vector3 x1(v1.getLocalXYZ()), x2(v2.getLocalXYZ()), x3(v3.getLocalXYZ());
+ MT_Vector2 uv1(v1.getUV1()), uv2(v2.getUV1()), uv3(v3.getUV1());
+ MT_Vector3 dx1(x2 - x1), dx2(x3 - x1);
+ MT_Vector2 duv1(uv2 - uv1), duv2(uv3 - uv1);
+
+ MT_Scalar r = 1.0 / (duv1.x() * duv2.y() - duv2.x() * duv1.y());
+ duv1 *= r;
+ duv2 *= r;
+ MT_Vector3 sdir(duv2.y() * dx1 - duv1.y() * dx2);
+ MT_Vector3 tdir(duv1.x() * dx2 - duv2.x() * dx1);
+
+ // Gram-Schmidt orthogonalize
+ MT_Vector3 t(sdir - no.cross(no.cross(sdir)));
+ if (!MT_fuzzyZero(t))
+ t /= t.length();
+
+ float tangent[4];
+ t.getValue(tangent);
+ // Calculate handedness
+ tangent[3] = no.dot(sdir.cross(tdir)) < 0.0 ? -1.0 : 1.0;
+#endif
+}
+
+
+void RAS_OpenGLRasterizer::IndexPrimitivesMulti(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot
+ )
+{
+#ifdef GL_ARB_multitexture
+
+ GLenum drawmode;
+ switch (mode)
+ {
+ case 0:
+ drawmode = GL_TRIANGLES;
+ break;
+ case 1:
+ drawmode = GL_LINES;
+ break;
+ case 2:
+ drawmode = GL_QUADS;
+ break;
+ default:
+ drawmode = GL_LINES;
+ break;
+ }
+
+ const RAS_TexVert* vertexarray ;
+ unsigned int numindices,vt;
+
+ for (vt=0;vt<vertexarrays.size();vt++)
+ {
+ vertexarray = &((*vertexarrays[vt]) [0]);
+ const KX_IndexArray & indexarray = (*indexarrays[vt]);
+ numindices = indexarray.size();
+ const unsigned int enabled = polymat->GetEnabled();
+
+ if (!numindices)
+ break;
+
+ int vindex=0;
+ switch (mode)
+ {
+ case 1:
+ {
+ glBegin(GL_LINES);
+ vindex=0;
+ for (unsigned int i=0;i<numindices;i+=2)
+ {
+ glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ());
+ glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ());
+ }
+ glEnd();
+ }
+ break;
+ case 2:
+ {
+ glBegin(GL_QUADS);
+ vindex=0;
+ if (useObjectColor)
+ {
+ for (unsigned int i=0;i<numindices;i+=4)
+ {
+
+ glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]);
+
+ //
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ //
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ //
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ //
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ else
+ {
+ for (unsigned int i=0;i<numindices;i+=4)
+ {
+ // This looks curiously endian unsafe to me.
+ // However it depends on the way the colors are packed into
+ // the m_rgba field of RAS_TexVert
+
+ //
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ //
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ //
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ //
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ glEnd();
+ break;
+ }
+ case 0:
+ {
+ glBegin(GL_TRIANGLES);
+ vindex=0;
+ if (useObjectColor)
+ {
+ for (unsigned int i=0;i<numindices;i+=3)
+ {
+
+ glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]);
+ //
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ //
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ //
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ else
+ {
+ for (unsigned int i=0;i<numindices;i+=3)
+ {
+ //
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ //
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ //
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ glEnd();
+ break;
+ }
+ default:
+ {
+ }
+ } // switch
+ } // for each vertexarray
+#endif// GL_ARB_multitexture
+
+}
+
+void RAS_OpenGLRasterizer::IndexPrimitivesMulti_Ex(
+ const vecVertexArray & vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor)
+{
+#ifdef GL_ARB_multitexture
+ bool recalc;
+ GLenum drawmode;
+ switch (mode)
+ {
+ case 0:
+ drawmode = GL_TRIANGLES;
+ break;
+ case 1:
+ drawmode = GL_LINES;
+ break;
+ case 2:
+ drawmode = GL_QUADS;
+ break;
+ default:
+ drawmode = GL_LINES;
+ break;
+ }
+
+ const RAS_TexVert* vertexarray ;
+ unsigned int numindices,vt;
+
+ for (vt=0;vt<vertexarrays.size();vt++)
+ {
+ vertexarray = &((*vertexarrays[vt]) [0]);
+ const KX_IndexArray & indexarray = (*indexarrays[vt]);
+ numindices = indexarray.size();
+ const unsigned int enabled = polymat->GetEnabled();
+
+ if (!numindices)
+ continue;
+
+ int vindex=0;
+ switch (mode)
+ {
+ case 1:
+ {
+ glBegin(GL_LINES);
+ vindex=0;
+ for (unsigned int i=0;i<numindices;i+=2)
+ {
+ glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ());
+ glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ());
+ }
+ glEnd();
+ }
+ break;
+ case 2:
+ {
+ glBegin(GL_QUADS);
+ vindex=0;
+ if (useObjectColor)
+ {
+ for (unsigned int i=0;i<numindices;i+=4)
+ {
+ MT_Point3 mv1, mv2, mv3, mv4, fnor;
+ /* Calc a new face normal */
+
+ if (vertexarray[(indexarray[vindex])].getFlag() & TV_CALCFACENORMAL)
+ recalc= true;
+ else
+ recalc=false;
+
+ if (recalc){
+ mv1 = MT_Point3(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ mv2 = MT_Point3(vertexarray[(indexarray[vindex+1])].getLocalXYZ());
+ mv3 = MT_Point3(vertexarray[(indexarray[vindex+2])].getLocalXYZ());
+ mv4 = MT_Point3(vertexarray[(indexarray[vindex+2])].getLocalXYZ());
+
+ fnor = (((mv2-mv1).cross(mv3-mv2))+((mv4-mv3).cross(mv1-mv4))).safe_normalized();
+
+ glNormal3f(fnor[0], fnor[1], fnor[2]);
+ }
+
+ glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]);
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ else
+ {
+ for (unsigned int i=0;i<numindices;i+=4)
+ {
+ // This looks curiously endian unsafe to me.
+ // However it depends on the way the colors are packed into
+ // the m_rgba field of RAS_TexVert
+ MT_Point3 mv1, mv2, mv3, mv4, fnor;
+ /* Calc a new face normal */
+
+ if (vertexarray[(indexarray[vindex])].getFlag() & TV_CALCFACENORMAL)
+ recalc= true;
+ else
+ recalc=false;
+
+
+ if (recalc){
+ mv1 = MT_Point3(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ mv2 = MT_Point3(vertexarray[(indexarray[vindex+1])].getLocalXYZ());
+ mv3 = MT_Point3(vertexarray[(indexarray[vindex+2])].getLocalXYZ());
+ mv4 = MT_Point3(vertexarray[(indexarray[vindex+3])].getLocalXYZ());
+
+ fnor = (((mv2-mv1).cross(mv3-mv2))+((mv4-mv3).cross(mv1-mv4))).safe_normalized();
+
+ glNormal3f(fnor[0], fnor[1], fnor[2]);
+ }
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ glEnd();
+ break;
+ }
+ case 0:
+ {
+ glBegin(GL_TRIANGLES);
+ vindex=0;
+ if (useObjectColor)
+ {
+ for (unsigned int i=0;i<numindices;i+=3)
+ {
+ MT_Point3 mv1, mv2, mv3, fnor;
+ /* Calc a new face normal */
+
+ if (vertexarray[(indexarray[vindex])].getFlag() & TV_CALCFACENORMAL)
+ recalc= true;
+ else
+ recalc=false;
+
+ if (recalc){
+ mv1 = MT_Point3(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ mv2 = MT_Point3(vertexarray[(indexarray[vindex+1])].getLocalXYZ());
+ mv3 = MT_Point3(vertexarray[(indexarray[vindex+2])].getLocalXYZ());
+
+ fnor = ((mv2-mv1).cross(mv3-mv2)).safe_normalized();
+ glNormal3f(fnor[0], fnor[1], fnor[2]);
+ }
+
+ glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]);
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ else
+ {
+ for (unsigned int i=0;i<numindices;i+=3)
+ {
+ MT_Point3 mv1, mv2, mv3, fnor;
+ /* Calc a new face normal */
+
+ if (vertexarray[(indexarray[vindex])].getFlag() & TV_CALCFACENORMAL)
+ recalc= true;
+ else
+ recalc=false;
+
+
+ if (recalc){
+ mv1 = MT_Point3(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ mv2 = MT_Point3(vertexarray[(indexarray[vindex+1])].getLocalXYZ());
+ mv3 = MT_Point3(vertexarray[(indexarray[vindex+2])].getLocalXYZ());
+
+ fnor = ((mv2-mv1).cross(mv3-mv2)).safe_normalized();
+ glNormal3f(fnor[0], fnor[1], fnor[2]);
+ }
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+
+ glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA()));
+ if (!recalc)
+ glNormal3fv(vertexarray[(indexarray[vindex])].getNormal());
+ TexCoord(vertexarray[(indexarray[vindex])],enabled );
+ glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ());
+ vindex++;
+ }
+ }
+ glEnd();
+ break;
+ }
+ default:
+ {
+ }
+
+ } // switch
+ } // for each vertexarray
+#endif
+}
+
+
+
+void RAS_OpenGLRasterizer::SetProjectionMatrix(MT_CmMatrix4x4 &mat)
+{
+ glMatrixMode(GL_PROJECTION);
+ double* matrix = &mat(0,0);
+ glLoadMatrixd(matrix);
+}
+
+
+void RAS_OpenGLRasterizer::SetProjectionMatrix(const MT_Matrix4x4 & mat)
+{
+ glMatrixMode(GL_PROJECTION);
+ double matrix[16];
+ /* Get into argument. Looks a bit dodgy, but it's ok. */
+ mat.getValue(matrix);
+ /* Internally, MT_Matrix4x4 uses doubles (MT_Scalar). */
+ glLoadMatrixd(matrix);
+}
+
+MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix(
+ float left,
+ float right,
+ float bottom,
+ float top,
+ float frustnear,
+ float frustfar,
+ bool
+){
+ MT_Matrix4x4 result;
+ double mat[16];
+
+ // correction for stereo
+ if(m_stereomode != RAS_STEREO_NOSTEREO)
+ {
+ float near_div_focallength;
+ // next 2 params should be specified on command line and in Blender publisher
+ if (!m_setfocallength)
+ m_focallength = 1.5 * right; // derived from example
+ if (!m_seteyesep)
+ m_eyeseparation = 0.18 * right; // just a guess...
+
+ near_div_focallength = frustnear / m_focallength;
+ switch(m_curreye)
+ {
+ case RAS_STEREO_LEFTEYE:
+ left += 0.5 * m_eyeseparation * near_div_focallength;
+ right += 0.5 * m_eyeseparation * near_div_focallength;
+ break;
+ case RAS_STEREO_RIGHTEYE:
+ left -= 0.5 * m_eyeseparation * near_div_focallength;
+ right -= 0.5 * m_eyeseparation * near_div_focallength;
+ break;
+ }
+ // leave bottom, top, bottom and top untouched
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(left, right, bottom, top, frustnear, frustfar);
+
+ glGetDoublev(GL_PROJECTION_MATRIX, mat);
+ result.setValue(mat);
+
+ return result;
+}
+
+
+// next arguments probably contain redundant info, for later...
+void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Vector3& campos,
+ const MT_Point3 &, const MT_Quaternion &camOrientQuat)
+{
+ MT_Matrix4x4 viewMat = mat;
+
+ // correction for stereo
+ if(m_stereomode != RAS_STEREO_NOSTEREO)
+ {
+ MT_Matrix3x3 camOrientMat3x3(camOrientQuat);
+ MT_Vector3 unitViewDir(0.0, -1.0, 0.0); // minus y direction, Blender convention
+ MT_Vector3 unitViewupVec(0.0, 0.0, 1.0);
+ MT_Vector3 viewDir, viewupVec;
+ MT_Vector3 eyeline;
+
+ // actual viewDir
+ viewDir = camOrientMat3x3 * unitViewDir; // this is the moto convention, vector on right hand side
+ // actual viewup vec
+ viewupVec = camOrientMat3x3 * unitViewupVec;
+
+ // vector between eyes
+ eyeline = viewDir.cross(viewupVec);
+
+ switch(m_curreye)
+ {
+ case RAS_STEREO_LEFTEYE:
+ {
+ // translate to left by half the eye distance
+ MT_Transform transform;
+ transform.setIdentity();
+ transform.translate(-(eyeline * m_eyeseparation / 2.0));
+ viewMat *= transform;
+ }
+ break;
+ case RAS_STEREO_RIGHTEYE:
+ {
+ // translate to right by half the eye distance
+ MT_Transform transform;
+ transform.setIdentity();
+ transform.translate(eyeline * m_eyeseparation / 2.0);
+ viewMat *= transform;
+ }
+ break;
+ }
+ }
+
+ // convert row major matrix 'viewMat' to column major for OpenGL
+ MT_Scalar cammat[16];
+ viewMat.getValue(cammat);
+ MT_CmMatrix4x4 viewCmmat = cammat;
+
+ glMatrixMode(GL_MODELVIEW);
+ m_viewmatrix = viewCmmat;
+ glLoadMatrixd(&m_viewmatrix(0,0));
+ m_campos = campos;
+}
+
+
+const MT_Point3& RAS_OpenGLRasterizer::GetCameraPosition()
+{
+ return m_campos;
+}
+
+
+
+void RAS_OpenGLRasterizer::LoadViewMatrix()
+{
+ glLoadMatrixd(&m_viewmatrix(0,0));
+}
+
+
+
+void RAS_OpenGLRasterizer::EnableTextures(bool enable)
+{
+}
+
+
+
+void RAS_OpenGLRasterizer::SetCullFace(bool enable)
+{
+ if (enable)
+ glEnable(GL_CULL_FACE);
+ else
+ glDisable(GL_CULL_FACE);
+}
+
+void RAS_OpenGLRasterizer::SetLines(bool enable)
+{
+ if (enable)
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ else
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+void RAS_OpenGLRasterizer::SetSpecularity(float specX,
+ float specY,
+ float specZ,
+ float specval)
+{
+ GLfloat mat_specular[] = {specX, specY, specZ, specval};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+}
+
+
+
+void RAS_OpenGLRasterizer::SetShinyness(float shiny)
+{
+ GLfloat mat_shininess[] = { shiny };
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+}
+
+
+
+void RAS_OpenGLRasterizer::SetDiffuse(float difX,float difY,float difZ,float diffuse)
+{
+ GLfloat mat_diffuse [] = {difX, difY,difZ, diffuse};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+}
+
+void RAS_OpenGLRasterizer::SetEmissive(float eX, float eY, float eZ, float e)
+{
+ GLfloat mat_emit [] = {eX,eY,eZ,e};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mat_emit);
+}
+
+
+double RAS_OpenGLRasterizer::GetTime()
+{
+ return m_time;
+}
+
+void RAS_OpenGLRasterizer::SetPolygonOffset(float mult, float add)
+{
+ glPolygonOffset(mult, add);
+ GLint mode = GL_POLYGON_OFFSET_FILL;
+ if (m_drawingmode < KX_SHADED)
+ mode = GL_POLYGON_OFFSET_LINE;
+ if (mult != 0.0f || add != 0.0f)
+ glEnable(mode);
+ else
+ glDisable(mode);
+}
+
+void RAS_OpenGLRasterizer::EnableMotionBlur(float motionblurvalue)
+{
+ m_motionblur = 1;
+ m_motionblurvalue = motionblurvalue;
+}
+
+void RAS_OpenGLRasterizer::DisableMotionBlur()
+{
+ m_motionblur = 0;
+ m_motionblurvalue = -1.0;
+}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
new file mode 100644
index 00000000000..6728905aa57
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
@@ -0,0 +1,318 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __RAS_OPENGLRASTERIZER
+#define __RAS_OPENGLRASTERIZER
+
+#ifdef WIN32
+#pragma warning (disable:4786)
+#endif
+
+#include "MT_CmMatrix4x4.h"
+#include <vector>
+using namespace std;
+
+#include "RAS_IRasterizer.h"
+#include "RAS_MaterialBucket.h"
+#include "RAS_ICanvas.h"
+
+#define RAS_MAX 3// match in BL_Material
+
+struct OglDebugLine
+{
+ MT_Vector3 m_from;
+ MT_Vector3 m_to;
+ MT_Vector3 m_color;
+};
+
+/**
+ * 3D rendering device context.
+ */
+class RAS_OpenGLRasterizer : public RAS_IRasterizer
+{
+
+ RAS_ICanvas* m_2DCanvas;
+
+ // fogging vars
+ bool m_fogenabled;
+ float m_fogstart;
+ float m_fogdist;
+ float m_fogr;
+ float m_fogg;
+ float m_fogb;
+
+ float m_redback;
+ float m_greenback;
+ float m_blueback;
+ float m_alphaback;
+
+ float m_ambr;
+ float m_ambg;
+ float m_ambb;
+
+ double m_time;
+ MT_CmMatrix4x4 m_viewmatrix;
+ MT_Point3 m_campos;
+
+ StereoMode m_stereomode;
+ StereoEye m_curreye;
+ float m_eyeseparation;
+ bool m_seteyesep;
+ float m_focallength;
+ bool m_setfocallength;
+ int m_noOfScanlines;
+ bool InterlacedStereo() const;
+
+ //motion blur
+ int m_motionblur;
+ float m_motionblurvalue;
+
+protected:
+ int m_drawingmode;
+ TexCoGen m_texco[RAS_MAX];
+ bool m_useTang;
+
+ /** Stores the caching information for the last material activated. */
+ RAS_IPolyMaterial::TCachingInfo m_materialCachingInfo;
+
+public:
+ double GetTime();
+ RAS_OpenGLRasterizer(RAS_ICanvas* canv);
+ virtual ~RAS_OpenGLRasterizer();
+
+ /*enum DrawType
+ {
+ KX_BOUNDINGBOX = 1,
+ KX_WIREFRAME,
+ KX_SOLID,
+ KX_SHADED,
+ KX_TEXTURED
+ };
+
+ enum DepthMask
+ {
+ KX_DEPTHMASK_ENABLED =1,
+ KX_DEPTHMASK_DISABLED,
+ };*/
+ virtual void SetDepthMask(DepthMask depthmask);
+
+ virtual bool SetMaterial(const RAS_IPolyMaterial& mat);
+ virtual bool Init();
+ virtual void Exit();
+ virtual bool BeginFrame(int drawingmode, double time);
+ virtual void ClearDepthBuffer();
+ virtual void ClearCachingInfo(void);
+ virtual void EndFrame();
+ virtual void SetRenderArea();
+
+ virtual void SetStereoMode(const StereoMode stereomode);
+ virtual bool Stereo();
+ virtual void SetEye(const StereoEye eye);
+ virtual StereoEye GetEye();
+ virtual void SetEyeSeparation(const float eyeseparation);
+ virtual float GetEyeSeparation();
+ virtual void SetFocalLength(const float focallength);
+ virtual float GetFocalLength();
+
+ virtual void SetAlphaTest(bool enable);
+
+ virtual void SwapBuffers();
+ virtual void IndexPrimitives(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot
+ );
+
+ virtual void IndexPrimitives_Ex(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor
+ );
+
+ virtual void IndexPrimitives_3DText(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor
+ );
+
+ virtual void IndexPrimitivesMulti(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot);
+
+ virtual void IndexPrimitivesMulti_Ex(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor);
+
+
+ virtual void SetProjectionMatrix(MT_CmMatrix4x4 & mat);
+ virtual void SetProjectionMatrix(const MT_Matrix4x4 & mat);
+ virtual void SetViewMatrix(
+ const MT_Matrix4x4 & mat,
+ const MT_Vector3& campos,
+ const MT_Point3 &camLoc,
+ const MT_Quaternion &camOrientQuat
+ );
+
+ virtual const MT_Point3& GetCameraPosition();
+ virtual void LoadViewMatrix();
+
+ virtual void SetFog(
+ float start,
+ float dist,
+ float r,
+ float g,
+ float b
+ );
+
+ virtual void SetFogColor(
+ float r,
+ float g,
+ float b
+ );
+
+ virtual void SetFogStart(float fogstart);
+ virtual void SetFogEnd(float fogend);
+
+ void DisableFog();
+ virtual void DisplayFog();
+
+ virtual void SetBackColor(
+ float red,
+ float green,
+ float blue,
+ float alpha
+ );
+
+ virtual void SetDrawingMode(int drawingmode);
+ virtual int GetDrawingMode();
+
+ virtual void EnableTextures(bool enable);
+ virtual void SetCullFace(bool enable);
+ virtual void SetLines(bool enable);
+
+ virtual MT_Matrix4x4 GetFrustumMatrix(
+ float left,
+ float right,
+ float bottom,
+ float top,
+ float frustnear,
+ float frustfar,
+ bool perspective
+ );
+
+ virtual void SetSpecularity(
+ float specX,
+ float specY,
+ float specZ,
+ float specval
+ );
+
+ virtual void SetShinyness(float shiny);
+ virtual void SetDiffuse(
+ float difX,
+ float difY,
+ float difZ,
+ float diffuse
+ );
+ virtual void SetEmissive(float eX,
+ float eY,
+ float eZ,
+ float e
+ );
+
+ virtual void SetAmbientColor(float red, float green, float blue);
+ virtual void SetAmbient(float factor);
+
+ virtual void SetPolygonOffset(float mult, float add);
+
+ virtual void DrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color)
+ {
+ OglDebugLine line;
+ line.m_from = from;
+ line.m_to = to;
+ line.m_color = color;
+ m_debugLines.push_back(line);
+ }
+
+ std::vector <OglDebugLine> m_debugLines;
+
+ virtual void SetTexCoords(TexCoGen coords,int enabled);
+ virtual void SetAttrib(int type);
+ void TexCoord(const RAS_TexVert &tv, int unit);
+ virtual void GetViewMatrix(MT_Matrix4x4 &mat) const;
+
+ void Tangent(const RAS_TexVert& v1,
+ const RAS_TexVert& v2,
+ const RAS_TexVert& v3,
+ const MT_Vector3 &no);
+
+ virtual void EnableMotionBlur(float motionblurvalue);
+ virtual void DisableMotionBlur();
+ virtual float GetMotionBlurValue(){return m_motionblurvalue;};
+ virtual int GetMotionBlurState(){return m_motionblur;};
+ virtual void SetMotionBlurState(int newstate)
+ {
+ if(newstate<0)
+ m_motionblur = 0;
+ else if(newstate>2)
+ m_motionblur = 2;
+ else
+ m_motionblur = newstate;
+ };
+};
+
+#endif //__RAS_OPENGLRASTERIZER
+
+
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp
new file mode 100644
index 00000000000..246b1ae74a1
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp
@@ -0,0 +1,352 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "RAS_VAOpenGLRasterizer.h"
+
+#ifdef WIN32
+#include <windows.h>
+#endif // WIN32
+#ifdef __APPLE__
+#define GL_GLEXT_LEGACY 1
+#include <OpenGL/gl.h>
+#else
+#include <GL/gl.h>
+#endif
+
+#include "STR_String.h"
+#include "RAS_TexVert.h"
+#include "MT_CmMatrix4x4.h"
+#include "RAS_IRenderTools.h" // rendering text
+
+#include "RAS_GLExtensionManager.h"
+
+
+using namespace bgl;
+
+RAS_VAOpenGLRasterizer::RAS_VAOpenGLRasterizer(RAS_ICanvas* canvas, bool lock)
+: RAS_OpenGLRasterizer(canvas),
+ m_Lock(lock && RAS_EXT_support._EXT_compiled_vertex_array)
+{
+}
+
+
+
+RAS_VAOpenGLRasterizer::~RAS_VAOpenGLRasterizer()
+{
+}
+
+bool RAS_VAOpenGLRasterizer::Init(void)
+{
+
+ bool result = RAS_OpenGLRasterizer::Init();
+
+ if (result)
+ {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+
+ return result;
+}
+
+
+
+void RAS_VAOpenGLRasterizer::SetDrawingMode(int drawingmode)
+{
+ m_drawingmode = drawingmode;
+
+ switch (m_drawingmode)
+ {
+ case KX_BOUNDINGBOX:
+ {
+ }
+ case KX_WIREFRAME:
+ {
+ glDisable (GL_CULL_FACE);
+ break;
+ }
+ case KX_TEXTURED:
+ {
+ }
+ case KX_SHADED:
+ {
+ glEnableClientState(GL_COLOR_ARRAY);
+ }
+ case KX_SOLID:
+ {
+ break;
+ }
+ default:
+ {
+ }
+ }
+}
+
+
+
+void RAS_VAOpenGLRasterizer::Exit()
+{
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+
+ RAS_OpenGLRasterizer::Exit();
+}
+
+
+
+void RAS_VAOpenGLRasterizer::IndexPrimitives( const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot)
+{
+ static const GLsizei vtxstride = sizeof(RAS_TexVert);
+ GLenum drawmode;
+ switch (mode)
+ {
+ case 0:
+ {
+ drawmode = GL_TRIANGLES;
+ break;
+ }
+ case 2:
+ {
+ drawmode = GL_QUADS;
+ break;
+ }
+ case 1: //lines
+ {
+ }
+ default:
+ {
+ drawmode = GL_LINES;
+ break;
+ }
+ }
+ const RAS_TexVert* vertexarray;
+ unsigned int numindices, vt;
+ if (drawmode != GL_LINES)
+ {
+ if (useObjectColor)
+ {
+ glDisableClientState(GL_COLOR_ARRAY);
+ glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]);
+ } else
+ {
+ glColor4d(0,0,0,1.0);
+ glEnableClientState(GL_COLOR_ARRAY);
+ }
+ }
+ else
+ {
+ glColor3d(0,0,0);
+ }
+
+ // use glDrawElements to draw each vertexarray
+ for (vt=0;vt<vertexarrays.size();vt++)
+ {
+ vertexarray = &((*vertexarrays[vt]) [0]);
+ const KX_IndexArray & indexarray = (*indexarrays[vt]);
+ numindices = indexarray.size();
+
+ if (!numindices)
+ continue;
+
+ glVertexPointer(3,GL_FLOAT,vtxstride,vertexarray->getLocalXYZ());
+ glTexCoordPointer(2,GL_FLOAT,vtxstride,vertexarray->getUV1());
+ glColorPointer(4,GL_UNSIGNED_BYTE,vtxstride,vertexarray->getRGBA());
+ glNormalPointer(GL_FLOAT,vtxstride,vertexarray->getNormal());
+
+ //if(m_Lock)
+ // local->Begin(vertexarrays[vt]->size());
+
+ // here the actual drawing takes places
+ glDrawElements(drawmode,numindices,GL_UNSIGNED_SHORT,&(indexarray[0]));
+
+ //if(m_Lock)
+ // local->End();
+
+
+ }
+}
+
+
+void RAS_VAOpenGLRasterizer::IndexPrimitivesMulti( const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot)
+{
+ static const GLsizei vtxstride = sizeof(RAS_TexVert);
+ GLenum drawmode;
+ switch (mode)
+ {
+ case 0:
+ {
+ drawmode = GL_TRIANGLES;
+ break;
+ }
+ case 2:
+ {
+ drawmode = GL_QUADS;
+ break;
+ }
+ case 1: //lines
+ {
+ }
+ default:
+ {
+ drawmode = GL_LINES;
+ break;
+ }
+ }
+ const RAS_TexVert* vertexarray;
+ unsigned int numindices, vt;
+ const unsigned int enabled = polymat->GetEnabled();
+
+ if (drawmode != GL_LINES)
+ {
+ if (useObjectColor)
+ {
+ glDisableClientState(GL_COLOR_ARRAY);
+ glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]);
+ } else
+ {
+ glColor4d(0,0,0,1.0);
+ glEnableClientState(GL_COLOR_ARRAY);
+ }
+ }
+ else
+ {
+ glColor3d(0,0,0);
+ }
+
+ // use glDrawElements to draw each vertexarray
+ for (vt=0;vt<vertexarrays.size();vt++)
+ {
+ vertexarray = &((*vertexarrays[vt]) [0]);
+ const KX_IndexArray & indexarray = (*indexarrays[vt]);
+ numindices = indexarray.size();
+
+ if (!numindices)
+ continue;
+
+ glVertexPointer(3,GL_FLOAT,vtxstride,vertexarray->getLocalXYZ());
+ TexCoordPtr(vertexarray, enabled);
+
+ //glTexCoordPointer(2,GL_FLOAT,vtxstride,vertexarray->getUV1());
+ glColorPointer(4,GL_UNSIGNED_BYTE,vtxstride,vertexarray->getRGBA());
+ glNormalPointer(GL_FLOAT,vtxstride,vertexarray->getNormal());
+
+ //if(m_Lock)
+ // local->Begin(vertexarrays[vt]->size());
+
+ // here the actual drawing takes places
+ glDrawElements(drawmode,numindices,GL_UNSIGNED_SHORT,&(indexarray[0]));
+
+ //if(m_Lock)
+ // local->End();
+ }
+}
+
+void RAS_VAOpenGLRasterizer::TexCoordPtr(const RAS_TexVert *tv, int enabled)
+{
+#ifdef GL_ARB_multitexture
+ if(bgl::RAS_EXT_support._ARB_multitexture)
+ {
+ for(int unit=0; unit<enabled; unit++)
+ {
+ bgl::blClientActiveTextureARB(GL_TEXTURE0_ARB+unit);
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ if( tv->getFlag() & TV_2NDUV && tv->getUnit() == unit ) {
+ glTexCoordPointer(2, GL_FLOAT, sizeof(RAS_TexVert), tv->getUV2());
+ continue;
+ }
+ switch(m_texco[unit])
+ {
+ case RAS_TEXCO_DISABLE:
+ case RAS_TEXCO_OBJECT:
+ case RAS_TEXCO_GEN:
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ break;
+ case RAS_TEXCO_ORCO:
+ case RAS_TEXCO_GLOB:
+ glTexCoordPointer(3, GL_FLOAT, sizeof(RAS_TexVert),tv->getLocalXYZ());
+ break;
+ case RAS_TEXCO_UV1:
+ glTexCoordPointer(2, GL_FLOAT, sizeof(RAS_TexVert),tv->getUV1());
+ break;
+ case RAS_TEXCO_NORM:
+ glTexCoordPointer(3, GL_FLOAT, sizeof(RAS_TexVert),tv->getNormal());
+ break;
+ case RAS_TEXTANGENT:
+ glTexCoordPointer(4, GL_FLOAT, sizeof(RAS_TexVert),tv->getTangent());
+ break;
+ case RAS_TEXCO_UV2:
+ glTexCoordPointer(2, GL_FLOAT, sizeof(RAS_TexVert),tv->getUV2());
+ break;
+ }
+ }
+ }
+
+#ifdef GL_ARB_vertex_program
+ if(m_useTang && bgl::RAS_EXT_support._ARB_vertex_program)
+ bgl::blVertexAttrib4fvARB(1/*tangent*/, tv->getTangent());
+#endif
+
+#endif
+}
+
+
+void RAS_VAOpenGLRasterizer::EnableTextures(bool enable)
+{
+ if (enable)
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ else
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h
new file mode 100644
index 00000000000..06a6fb4bb3a
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.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 *****
+ */
+#ifndef __KX_VERTEXARRAYOPENGLRASTERIZER
+#define __KX_VERTEXARRAYOPENGLRASTERIZER
+
+#include "RAS_OpenGLRasterizer.h"
+
+class RAS_VAOpenGLRasterizer : public RAS_OpenGLRasterizer
+{
+ void TexCoordPtr(const RAS_TexVert *tv, int unit);
+ bool m_Lock;
+
+public:
+ RAS_VAOpenGLRasterizer(RAS_ICanvas* canvas, bool lock=false);
+ virtual ~RAS_VAOpenGLRasterizer();
+
+ virtual bool Init();
+ virtual void Exit();
+
+ virtual void SetDrawingMode(int drawingmode);
+
+ virtual void IndexPrimitives( const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot);
+
+ virtual void IndexPrimitivesMulti(
+ const vecVertexArray& vertexarrays,
+ const vecIndexArrays & indexarrays,
+ int mode,
+ class RAS_IPolyMaterial* polymat,
+ class RAS_IRenderTools* rendertools,
+ bool useObjectColor,
+ const MT_Vector4& rgbacolor,
+ class KX_ListSlot** slot);
+
+
+ virtual void EnableTextures(bool enable);
+ //virtual bool QueryArrays(){return true;}
+ //virtual bool QueryLists(){return m_Lock;}
+
+};
+
+#endif //__KX_VERTEXARRAYOPENGLRASTERIZER
+
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript
new file mode 100644
index 00000000000..039bc3db8df
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('*.cpp') #'RAS_GLExtensionManager.cpp RAS_ListRasterizer.cpp RAS_OpenGLRasterizer.cpp RAS_VAOpenGLRasterizer.cpp'
+
+incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/Rasterizer'
+incs += ' ' + env['BF_OPENGL_INC']
+
+env.BlenderLib ( 'bf_oglrasterizer', Split(sources), Split(incs), [], libtype=['game','player'], priority=[40, 120] )
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/glext.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/glext.h
new file mode 100644
index 00000000000..7bb8e6e7cc7
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/glext.h
@@ -0,0 +1,6495 @@
+#ifndef __glext_h_
+#define __glext_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: This software was created using the
+** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has
+** not been independently verified as being compliant with the OpenGL(R)
+** version 1.2.1 Specification.
+*/
+
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+
+/*************************************************************/
+
+/* Header file version number, required by OpenGL ABI for Linux */
+/* glext.h last updated 2005/06/20 */
+/* Current version at http://oss.sgi.com/projects/ogl-sample/registry/ */
+#define GL_GLEXT_VERSION 29
+
+#ifndef GL_VERSION_1_2
+#define GL_UNSIGNED_BYTE_3_3_2 0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_INT_8_8_8_8 0x8035
+#define GL_UNSIGNED_INT_10_10_10_2 0x8036
+#define GL_RESCALE_NORMAL 0x803A
+#define GL_TEXTURE_BINDING_3D 0x806A
+#define GL_PACK_SKIP_IMAGES 0x806B
+#define GL_PACK_IMAGE_HEIGHT 0x806C
+#define GL_UNPACK_SKIP_IMAGES 0x806D
+#define GL_UNPACK_IMAGE_HEIGHT 0x806E
+#define GL_TEXTURE_3D 0x806F
+#define GL_PROXY_TEXTURE_3D 0x8070
+#define GL_TEXTURE_DEPTH 0x8071
+#define GL_TEXTURE_WRAP_R 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE 0x8073
+#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#define GL_BGR 0x80E0
+#define GL_BGRA 0x80E1
+#define GL_MAX_ELEMENTS_VERTICES 0x80E8
+#define GL_MAX_ELEMENTS_INDICES 0x80E9
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_TEXTURE_MIN_LOD 0x813A
+#define GL_TEXTURE_MAX_LOD 0x813B
+#define GL_TEXTURE_BASE_LEVEL 0x813C
+#define GL_TEXTURE_MAX_LEVEL 0x813D
+#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8
+#define GL_SINGLE_COLOR 0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR 0x81FA
+#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#endif
+
+#ifndef GL_ARB_imaging
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BLEND_COLOR 0x8005
+#define GL_FUNC_ADD 0x8006
+#define GL_MIN 0x8007
+#define GL_MAX 0x8008
+#define GL_BLEND_EQUATION 0x8009
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+#define GL_CONVOLUTION_1D 0x8010
+#define GL_CONVOLUTION_2D 0x8011
+#define GL_SEPARABLE_2D 0x8012
+#define GL_CONVOLUTION_BORDER_MODE 0x8013
+#define GL_CONVOLUTION_FILTER_SCALE 0x8014
+#define GL_CONVOLUTION_FILTER_BIAS 0x8015
+#define GL_REDUCE 0x8016
+#define GL_CONVOLUTION_FORMAT 0x8017
+#define GL_CONVOLUTION_WIDTH 0x8018
+#define GL_CONVOLUTION_HEIGHT 0x8019
+#define GL_MAX_CONVOLUTION_WIDTH 0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT 0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE 0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS 0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023
+#define GL_HISTOGRAM 0x8024
+#define GL_PROXY_HISTOGRAM 0x8025
+#define GL_HISTOGRAM_WIDTH 0x8026
+#define GL_HISTOGRAM_FORMAT 0x8027
+#define GL_HISTOGRAM_RED_SIZE 0x8028
+#define GL_HISTOGRAM_GREEN_SIZE 0x8029
+#define GL_HISTOGRAM_BLUE_SIZE 0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE 0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C
+#define GL_HISTOGRAM_SINK 0x802D
+#define GL_MINMAX 0x802E
+#define GL_MINMAX_FORMAT 0x802F
+#define GL_MINMAX_SINK 0x8030
+#define GL_TABLE_TOO_LARGE 0x8031
+#define GL_COLOR_MATRIX 0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB
+#define GL_COLOR_TABLE 0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2
+#define GL_PROXY_COLOR_TABLE 0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5
+#define GL_COLOR_TABLE_SCALE 0x80D6
+#define GL_COLOR_TABLE_BIAS 0x80D7
+#define GL_COLOR_TABLE_FORMAT 0x80D8
+#define GL_COLOR_TABLE_WIDTH 0x80D9
+#define GL_COLOR_TABLE_RED_SIZE 0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE 0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE 0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF
+#define GL_CONSTANT_BORDER 0x8151
+#define GL_REPLICATE_BORDER 0x8153
+#define GL_CONVOLUTION_BORDER_COLOR 0x8154
+#endif
+
+#ifndef GL_VERSION_1_3
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1
+#define GL_MAX_TEXTURE_UNITS 0x84E2
+#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6
+#define GL_MULTISAMPLE 0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
+#define GL_SAMPLE_COVERAGE 0x80A0
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+#define GL_MULTISAMPLE_BIT 0x20000000
+#define GL_NORMAL_MAP 0x8511
+#define GL_REFLECTION_MAP 0x8512
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+#define GL_COMPRESSED_ALPHA 0x84E9
+#define GL_COMPRESSED_LUMINANCE 0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB
+#define GL_COMPRESSED_INTENSITY 0x84EC
+#define GL_COMPRESSED_RGB 0x84ED
+#define GL_COMPRESSED_RGBA 0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT 0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0
+#define GL_TEXTURE_COMPRESSED 0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+#define GL_CLAMP_TO_BORDER 0x812D
+#define GL_COMBINE 0x8570
+#define GL_COMBINE_RGB 0x8571
+#define GL_COMBINE_ALPHA 0x8572
+#define GL_SOURCE0_RGB 0x8580
+#define GL_SOURCE1_RGB 0x8581
+#define GL_SOURCE2_RGB 0x8582
+#define GL_SOURCE0_ALPHA 0x8588
+#define GL_SOURCE1_ALPHA 0x8589
+#define GL_SOURCE2_ALPHA 0x858A
+#define GL_OPERAND0_RGB 0x8590
+#define GL_OPERAND1_RGB 0x8591
+#define GL_OPERAND2_RGB 0x8592
+#define GL_OPERAND0_ALPHA 0x8598
+#define GL_OPERAND1_ALPHA 0x8599
+#define GL_OPERAND2_ALPHA 0x859A
+#define GL_RGB_SCALE 0x8573
+#define GL_ADD_SIGNED 0x8574
+#define GL_INTERPOLATE 0x8575
+#define GL_SUBTRACT 0x84E7
+#define GL_CONSTANT 0x8576
+#define GL_PRIMARY_COLOR 0x8577
+#define GL_PREVIOUS 0x8578
+#define GL_DOT3_RGB 0x86AE
+#define GL_DOT3_RGBA 0x86AF
+#endif
+
+#ifndef GL_VERSION_1_4
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_POINT_SIZE_MIN 0x8126
+#define GL_POINT_SIZE_MAX 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128
+#define GL_POINT_DISTANCE_ATTENUATION 0x8129
+#define GL_GENERATE_MIPMAP 0x8191
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_DEPTH_COMPONENT24 0x81A6
+#define GL_DEPTH_COMPONENT32 0x81A7
+#define GL_MIRRORED_REPEAT 0x8370
+#define GL_FOG_COORDINATE_SOURCE 0x8450
+#define GL_FOG_COORDINATE 0x8451
+#define GL_FRAGMENT_DEPTH 0x8452
+#define GL_CURRENT_FOG_COORDINATE 0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456
+#define GL_FOG_COORDINATE_ARRAY 0x8457
+#define GL_COLOR_SUM 0x8458
+#define GL_CURRENT_SECONDARY_COLOR 0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D
+#define GL_SECONDARY_COLOR_ARRAY 0x845E
+#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
+#define GL_TEXTURE_FILTER_CONTROL 0x8500
+#define GL_TEXTURE_LOD_BIAS 0x8501
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+#define GL_TEXTURE_DEPTH_SIZE 0x884A
+#define GL_DEPTH_TEXTURE_MODE 0x884B
+#define GL_TEXTURE_COMPARE_MODE 0x884C
+#define GL_TEXTURE_COMPARE_FUNC 0x884D
+#define GL_COMPARE_R_TO_TEXTURE 0x884E
+#endif
+
+#ifndef GL_VERSION_1_5
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+#define GL_QUERY_COUNTER_BITS 0x8864
+#define GL_CURRENT_QUERY 0x8865
+#define GL_QUERY_RESULT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE 0x8867
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#define GL_READ_ONLY 0x88B8
+#define GL_WRITE_ONLY 0x88B9
+#define GL_READ_WRITE 0x88BA
+#define GL_BUFFER_ACCESS 0x88BB
+#define GL_BUFFER_MAPPED 0x88BC
+#define GL_BUFFER_MAP_POINTER 0x88BD
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STREAM_READ 0x88E1
+#define GL_STREAM_COPY 0x88E2
+#define GL_STATIC_DRAW 0x88E4
+#define GL_STATIC_READ 0x88E5
+#define GL_STATIC_COPY 0x88E6
+#define GL_DYNAMIC_DRAW 0x88E8
+#define GL_DYNAMIC_READ 0x88E9
+#define GL_DYNAMIC_COPY 0x88EA
+#define GL_SAMPLES_PASSED 0x8914
+#define GL_FOG_COORD_SRC GL_FOG_COORDINATE_SOURCE
+#define GL_FOG_COORD GL_FOG_COORDINATE
+#define GL_CURRENT_FOG_COORD GL_CURRENT_FOG_COORDINATE
+#define GL_FOG_COORD_ARRAY_TYPE GL_FOG_COORDINATE_ARRAY_TYPE
+#define GL_FOG_COORD_ARRAY_STRIDE GL_FOG_COORDINATE_ARRAY_STRIDE
+#define GL_FOG_COORD_ARRAY_POINTER GL_FOG_COORDINATE_ARRAY_POINTER
+#define GL_FOG_COORD_ARRAY GL_FOG_COORDINATE_ARRAY
+#define GL_FOG_COORD_ARRAY_BUFFER_BINDING GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING
+#define GL_SRC0_RGB GL_SOURCE0_RGB
+#define GL_SRC1_RGB GL_SOURCE1_RGB
+#define GL_SRC2_RGB GL_SOURCE2_RGB
+#define GL_SRC0_ALPHA GL_SOURCE0_ALPHA
+#define GL_SRC1_ALPHA GL_SOURCE1_ALPHA
+#define GL_SRC2_ALPHA GL_SOURCE2_ALPHA
+#endif
+
+#ifndef GL_VERSION_2_0
+#define GL_BLEND_EQUATION_RGB GL_BLEND_EQUATION
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_MAX_DRAW_BUFFERS 0x8824
+#define GL_DRAW_BUFFER0 0x8825
+#define GL_DRAW_BUFFER1 0x8826
+#define GL_DRAW_BUFFER2 0x8827
+#define GL_DRAW_BUFFER3 0x8828
+#define GL_DRAW_BUFFER4 0x8829
+#define GL_DRAW_BUFFER5 0x882A
+#define GL_DRAW_BUFFER6 0x882B
+#define GL_DRAW_BUFFER7 0x882C
+#define GL_DRAW_BUFFER8 0x882D
+#define GL_DRAW_BUFFER9 0x882E
+#define GL_DRAW_BUFFER10 0x882F
+#define GL_DRAW_BUFFER11 0x8830
+#define GL_DRAW_BUFFER12 0x8831
+#define GL_DRAW_BUFFER13 0x8832
+#define GL_DRAW_BUFFER14 0x8833
+#define GL_DRAW_BUFFER15 0x8834
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+#define GL_POINT_SPRITE 0x8861
+#define GL_COORD_REPLACE 0x8862
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_MAX_TEXTURE_COORDS 0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
+#define GL_MAX_VARYING_FLOATS 0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_1D 0x8B5D
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_3D 0x8B5F
+#define GL_SAMPLER_CUBE 0x8B60
+#define GL_SAMPLER_1D_SHADOW 0x8B61
+#define GL_SAMPLER_2D_SHADOW 0x8B62
+#define GL_DELETE_STATUS 0x8B80
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0
+#define GL_LOWER_LEFT 0x8CA1
+#define GL_UPPER_LEFT 0x8CA2
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#endif
+
+#ifndef GL_ARB_multitexture
+#define GL_TEXTURE0_ARB 0x84C0
+#define GL_TEXTURE1_ARB 0x84C1
+#define GL_TEXTURE2_ARB 0x84C2
+#define GL_TEXTURE3_ARB 0x84C3
+#define GL_TEXTURE4_ARB 0x84C4
+#define GL_TEXTURE5_ARB 0x84C5
+#define GL_TEXTURE6_ARB 0x84C6
+#define GL_TEXTURE7_ARB 0x84C7
+#define GL_TEXTURE8_ARB 0x84C8
+#define GL_TEXTURE9_ARB 0x84C9
+#define GL_TEXTURE10_ARB 0x84CA
+#define GL_TEXTURE11_ARB 0x84CB
+#define GL_TEXTURE12_ARB 0x84CC
+#define GL_TEXTURE13_ARB 0x84CD
+#define GL_TEXTURE14_ARB 0x84CE
+#define GL_TEXTURE15_ARB 0x84CF
+#define GL_TEXTURE16_ARB 0x84D0
+#define GL_TEXTURE17_ARB 0x84D1
+#define GL_TEXTURE18_ARB 0x84D2
+#define GL_TEXTURE19_ARB 0x84D3
+#define GL_TEXTURE20_ARB 0x84D4
+#define GL_TEXTURE21_ARB 0x84D5
+#define GL_TEXTURE22_ARB 0x84D6
+#define GL_TEXTURE23_ARB 0x84D7
+#define GL_TEXTURE24_ARB 0x84D8
+#define GL_TEXTURE25_ARB 0x84D9
+#define GL_TEXTURE26_ARB 0x84DA
+#define GL_TEXTURE27_ARB 0x84DB
+#define GL_TEXTURE28_ARB 0x84DC
+#define GL_TEXTURE29_ARB 0x84DD
+#define GL_TEXTURE30_ARB 0x84DE
+#define GL_TEXTURE31_ARB 0x84DF
+#define GL_ACTIVE_TEXTURE_ARB 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1
+#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2
+#endif
+
+#ifndef GL_ARB_transpose_matrix
+#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6
+#endif
+
+#ifndef GL_ARB_multisample
+#define GL_MULTISAMPLE_ARB 0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F
+#define GL_SAMPLE_COVERAGE_ARB 0x80A0
+#define GL_SAMPLE_BUFFERS_ARB 0x80A8
+#define GL_SAMPLES_ARB 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB
+#define GL_MULTISAMPLE_BIT_ARB 0x20000000
+#endif
+
+#ifndef GL_ARB_texture_env_add
+#endif
+
+#ifndef GL_ARB_texture_cube_map
+#define GL_NORMAL_MAP_ARB 0x8511
+#define GL_REFLECTION_MAP_ARB 0x8512
+#define GL_TEXTURE_CUBE_MAP_ARB 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C
+#endif
+
+#ifndef GL_ARB_texture_compression
+#define GL_COMPRESSED_ALPHA_ARB 0x84E9
+#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB
+#define GL_COMPRESSED_INTENSITY_ARB 0x84EC
+#define GL_COMPRESSED_RGB_ARB 0x84ED
+#define GL_COMPRESSED_RGBA_ARB 0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0
+#define GL_TEXTURE_COMPRESSED_ARB 0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3
+#endif
+
+#ifndef GL_ARB_texture_border_clamp
+#define GL_CLAMP_TO_BORDER_ARB 0x812D
+#endif
+
+#ifndef GL_ARB_point_parameters
+#define GL_POINT_SIZE_MIN_ARB 0x8126
+#define GL_POINT_SIZE_MAX_ARB 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128
+#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129
+#endif
+
+#ifndef GL_ARB_vertex_blend
+#define GL_MAX_VERTEX_UNITS_ARB 0x86A4
+#define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5
+#define GL_WEIGHT_SUM_UNITY_ARB 0x86A6
+#define GL_VERTEX_BLEND_ARB 0x86A7
+#define GL_CURRENT_WEIGHT_ARB 0x86A8
+#define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9
+#define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA
+#define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB
+#define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC
+#define GL_WEIGHT_ARRAY_ARB 0x86AD
+#define GL_MODELVIEW0_ARB 0x1700
+#define GL_MODELVIEW1_ARB 0x850A
+#define GL_MODELVIEW2_ARB 0x8722
+#define GL_MODELVIEW3_ARB 0x8723
+#define GL_MODELVIEW4_ARB 0x8724
+#define GL_MODELVIEW5_ARB 0x8725
+#define GL_MODELVIEW6_ARB 0x8726
+#define GL_MODELVIEW7_ARB 0x8727
+#define GL_MODELVIEW8_ARB 0x8728
+#define GL_MODELVIEW9_ARB 0x8729
+#define GL_MODELVIEW10_ARB 0x872A
+#define GL_MODELVIEW11_ARB 0x872B
+#define GL_MODELVIEW12_ARB 0x872C
+#define GL_MODELVIEW13_ARB 0x872D
+#define GL_MODELVIEW14_ARB 0x872E
+#define GL_MODELVIEW15_ARB 0x872F
+#define GL_MODELVIEW16_ARB 0x8730
+#define GL_MODELVIEW17_ARB 0x8731
+#define GL_MODELVIEW18_ARB 0x8732
+#define GL_MODELVIEW19_ARB 0x8733
+#define GL_MODELVIEW20_ARB 0x8734
+#define GL_MODELVIEW21_ARB 0x8735
+#define GL_MODELVIEW22_ARB 0x8736
+#define GL_MODELVIEW23_ARB 0x8737
+#define GL_MODELVIEW24_ARB 0x8738
+#define GL_MODELVIEW25_ARB 0x8739
+#define GL_MODELVIEW26_ARB 0x873A
+#define GL_MODELVIEW27_ARB 0x873B
+#define GL_MODELVIEW28_ARB 0x873C
+#define GL_MODELVIEW29_ARB 0x873D
+#define GL_MODELVIEW30_ARB 0x873E
+#define GL_MODELVIEW31_ARB 0x873F
+#endif
+
+#ifndef GL_ARB_matrix_palette
+#define GL_MATRIX_PALETTE_ARB 0x8840
+#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841
+#define GL_MAX_PALETTE_MATRICES_ARB 0x8842
+#define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843
+#define GL_MATRIX_INDEX_ARRAY_ARB 0x8844
+#define GL_CURRENT_MATRIX_INDEX_ARB 0x8845
+#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846
+#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847
+#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848
+#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849
+#endif
+
+#ifndef GL_ARB_texture_env_combine
+#define GL_COMBINE_ARB 0x8570
+#define GL_COMBINE_RGB_ARB 0x8571
+#define GL_COMBINE_ALPHA_ARB 0x8572
+#define GL_SOURCE0_RGB_ARB 0x8580
+#define GL_SOURCE1_RGB_ARB 0x8581
+#define GL_SOURCE2_RGB_ARB 0x8582
+#define GL_SOURCE0_ALPHA_ARB 0x8588
+#define GL_SOURCE1_ALPHA_ARB 0x8589
+#define GL_SOURCE2_ALPHA_ARB 0x858A
+#define GL_OPERAND0_RGB_ARB 0x8590
+#define GL_OPERAND1_RGB_ARB 0x8591
+#define GL_OPERAND2_RGB_ARB 0x8592
+#define GL_OPERAND0_ALPHA_ARB 0x8598
+#define GL_OPERAND1_ALPHA_ARB 0x8599
+#define GL_OPERAND2_ALPHA_ARB 0x859A
+#define GL_RGB_SCALE_ARB 0x8573
+#define GL_ADD_SIGNED_ARB 0x8574
+#define GL_INTERPOLATE_ARB 0x8575
+#define GL_SUBTRACT_ARB 0x84E7
+#define GL_CONSTANT_ARB 0x8576
+#define GL_PRIMARY_COLOR_ARB 0x8577
+#define GL_PREVIOUS_ARB 0x8578
+#endif
+
+#ifndef GL_ARB_texture_env_crossbar
+#endif
+
+#ifndef GL_ARB_texture_env_dot3
+#define GL_DOT3_RGB_ARB 0x86AE
+#define GL_DOT3_RGBA_ARB 0x86AF
+#endif
+
+#ifndef GL_ARB_texture_mirrored_repeat
+#define GL_MIRRORED_REPEAT_ARB 0x8370
+#endif
+
+#ifndef GL_ARB_depth_texture
+#define GL_DEPTH_COMPONENT16_ARB 0x81A5
+#define GL_DEPTH_COMPONENT24_ARB 0x81A6
+#define GL_DEPTH_COMPONENT32_ARB 0x81A7
+#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A
+#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B
+#endif
+
+#ifndef GL_ARB_shadow
+#define GL_TEXTURE_COMPARE_MODE_ARB 0x884C
+#define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D
+#define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E
+#endif
+
+#ifndef GL_ARB_shadow_ambient
+#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF
+#endif
+
+#ifndef GL_ARB_window_pos
+#endif
+
+#ifndef GL_ARB_vertex_program
+#define GL_COLOR_SUM_ARB 0x8458
+#define GL_VERTEX_PROGRAM_ARB 0x8620
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625
+#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626
+#define GL_PROGRAM_LENGTH_ARB 0x8627
+#define GL_PROGRAM_STRING_ARB 0x8628
+#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E
+#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F
+#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640
+#define GL_CURRENT_MATRIX_ARB 0x8641
+#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645
+#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B
+#define GL_PROGRAM_BINDING_ARB 0x8677
+#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A
+#define GL_PROGRAM_ERROR_STRING_ARB 0x8874
+#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875
+#define GL_PROGRAM_FORMAT_ARB 0x8876
+#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0
+#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1
+#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2
+#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3
+#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4
+#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5
+#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6
+#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7
+#define GL_PROGRAM_PARAMETERS_ARB 0x88A8
+#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9
+#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA
+#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB
+#define GL_PROGRAM_ATTRIBS_ARB 0x88AC
+#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD
+#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE
+#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF
+#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0
+#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1
+#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2
+#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3
+#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4
+#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5
+#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6
+#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7
+#define GL_MATRIX0_ARB 0x88C0
+#define GL_MATRIX1_ARB 0x88C1
+#define GL_MATRIX2_ARB 0x88C2
+#define GL_MATRIX3_ARB 0x88C3
+#define GL_MATRIX4_ARB 0x88C4
+#define GL_MATRIX5_ARB 0x88C5
+#define GL_MATRIX6_ARB 0x88C6
+#define GL_MATRIX7_ARB 0x88C7
+#define GL_MATRIX8_ARB 0x88C8
+#define GL_MATRIX9_ARB 0x88C9
+#define GL_MATRIX10_ARB 0x88CA
+#define GL_MATRIX11_ARB 0x88CB
+#define GL_MATRIX12_ARB 0x88CC
+#define GL_MATRIX13_ARB 0x88CD
+#define GL_MATRIX14_ARB 0x88CE
+#define GL_MATRIX15_ARB 0x88CF
+#define GL_MATRIX16_ARB 0x88D0
+#define GL_MATRIX17_ARB 0x88D1
+#define GL_MATRIX18_ARB 0x88D2
+#define GL_MATRIX19_ARB 0x88D3
+#define GL_MATRIX20_ARB 0x88D4
+#define GL_MATRIX21_ARB 0x88D5
+#define GL_MATRIX22_ARB 0x88D6
+#define GL_MATRIX23_ARB 0x88D7
+#define GL_MATRIX24_ARB 0x88D8
+#define GL_MATRIX25_ARB 0x88D9
+#define GL_MATRIX26_ARB 0x88DA
+#define GL_MATRIX27_ARB 0x88DB
+#define GL_MATRIX28_ARB 0x88DC
+#define GL_MATRIX29_ARB 0x88DD
+#define GL_MATRIX30_ARB 0x88DE
+#define GL_MATRIX31_ARB 0x88DF
+#endif
+
+#ifndef GL_ARB_fragment_program
+#define GL_FRAGMENT_PROGRAM_ARB 0x8804
+#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805
+#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806
+#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807
+#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808
+#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809
+#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A
+#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B
+#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C
+#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D
+#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E
+#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F
+#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810
+#define GL_MAX_TEXTURE_COORDS_ARB 0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_BUFFER_SIZE_ARB 0x8764
+#define GL_BUFFER_USAGE_ARB 0x8765
+#define GL_ARRAY_BUFFER_ARB 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893
+#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
+#define GL_READ_ONLY_ARB 0x88B8
+#define GL_WRITE_ONLY_ARB 0x88B9
+#define GL_READ_WRITE_ARB 0x88BA
+#define GL_BUFFER_ACCESS_ARB 0x88BB
+#define GL_BUFFER_MAPPED_ARB 0x88BC
+#define GL_BUFFER_MAP_POINTER_ARB 0x88BD
+#define GL_STREAM_DRAW_ARB 0x88E0
+#define GL_STREAM_READ_ARB 0x88E1
+#define GL_STREAM_COPY_ARB 0x88E2
+#define GL_STATIC_DRAW_ARB 0x88E4
+#define GL_STATIC_READ_ARB 0x88E5
+#define GL_STATIC_COPY_ARB 0x88E6
+#define GL_DYNAMIC_DRAW_ARB 0x88E8
+#define GL_DYNAMIC_READ_ARB 0x88E9
+#define GL_DYNAMIC_COPY_ARB 0x88EA
+#endif
+
+#ifndef GL_ARB_occlusion_query
+#define GL_QUERY_COUNTER_BITS_ARB 0x8864
+#define GL_CURRENT_QUERY_ARB 0x8865
+#define GL_QUERY_RESULT_ARB 0x8866
+#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867
+#define GL_SAMPLES_PASSED_ARB 0x8914
+#endif
+
+#ifndef GL_ARB_shader_objects
+#define GL_PROGRAM_OBJECT_ARB 0x8B40
+#define GL_SHADER_OBJECT_ARB 0x8B48
+#define GL_OBJECT_TYPE_ARB 0x8B4E
+#define GL_OBJECT_SUBTYPE_ARB 0x8B4F
+#define GL_FLOAT_VEC2_ARB 0x8B50
+#define GL_FLOAT_VEC3_ARB 0x8B51
+#define GL_FLOAT_VEC4_ARB 0x8B52
+#define GL_INT_VEC2_ARB 0x8B53
+#define GL_INT_VEC3_ARB 0x8B54
+#define GL_INT_VEC4_ARB 0x8B55
+#define GL_BOOL_ARB 0x8B56
+#define GL_BOOL_VEC2_ARB 0x8B57
+#define GL_BOOL_VEC3_ARB 0x8B58
+#define GL_BOOL_VEC4_ARB 0x8B59
+#define GL_FLOAT_MAT2_ARB 0x8B5A
+#define GL_FLOAT_MAT3_ARB 0x8B5B
+#define GL_FLOAT_MAT4_ARB 0x8B5C
+#define GL_SAMPLER_1D_ARB 0x8B5D
+#define GL_SAMPLER_2D_ARB 0x8B5E
+#define GL_SAMPLER_3D_ARB 0x8B5F
+#define GL_SAMPLER_CUBE_ARB 0x8B60
+#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61
+#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62
+#define GL_SAMPLER_2D_RECT_ARB 0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64
+#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80
+#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81
+#define GL_OBJECT_LINK_STATUS_ARB 0x8B82
+#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83
+#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84
+#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85
+#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86
+#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87
+#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88
+#endif
+
+#ifndef GL_ARB_vertex_shader
+#define GL_VERTEX_SHADER_ARB 0x8B31
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A
+#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D
+#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89
+#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
+#endif
+
+#ifndef GL_ARB_fragment_shader
+#define GL_FRAGMENT_SHADER_ARB 0x8B30
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
+#endif
+
+#ifndef GL_ARB_shading_language_100
+#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C
+#endif
+
+#ifndef GL_ARB_texture_non_power_of_two
+#endif
+
+#ifndef GL_ARB_point_sprite
+#define GL_POINT_SPRITE_ARB 0x8861
+#define GL_COORD_REPLACE_ARB 0x8862
+#endif
+
+#ifndef GL_ARB_fragment_program_shadow
+#endif
+
+#ifndef GL_ARB_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_ARB 0x8824
+#define GL_DRAW_BUFFER0_ARB 0x8825
+#define GL_DRAW_BUFFER1_ARB 0x8826
+#define GL_DRAW_BUFFER2_ARB 0x8827
+#define GL_DRAW_BUFFER3_ARB 0x8828
+#define GL_DRAW_BUFFER4_ARB 0x8829
+#define GL_DRAW_BUFFER5_ARB 0x882A
+#define GL_DRAW_BUFFER6_ARB 0x882B
+#define GL_DRAW_BUFFER7_ARB 0x882C
+#define GL_DRAW_BUFFER8_ARB 0x882D
+#define GL_DRAW_BUFFER9_ARB 0x882E
+#define GL_DRAW_BUFFER10_ARB 0x882F
+#define GL_DRAW_BUFFER11_ARB 0x8830
+#define GL_DRAW_BUFFER12_ARB 0x8831
+#define GL_DRAW_BUFFER13_ARB 0x8832
+#define GL_DRAW_BUFFER14_ARB 0x8833
+#define GL_DRAW_BUFFER15_ARB 0x8834
+#endif
+
+#ifndef GL_ARB_texture_rectangle
+#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+#endif
+
+#ifndef GL_ARB_color_buffer_float
+#define GL_RGBA_FLOAT_MODE_ARB 0x8820
+#define GL_CLAMP_VERTEX_COLOR_ARB 0x891A
+#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B
+#define GL_CLAMP_READ_COLOR_ARB 0x891C
+#define GL_FIXED_ONLY_ARB 0x891D
+#endif
+
+#ifndef GL_ARB_half_float_pixel
+#define GL_HALF_FLOAT_ARB 0x140B
+#endif
+
+#ifndef GL_ARB_texture_float
+#define GL_TEXTURE_RED_TYPE_ARB 0x8C10
+#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11
+#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12
+#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13
+#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14
+#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15
+#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16
+#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17
+#define GL_RGBA32F_ARB 0x8814
+#define GL_RGB32F_ARB 0x8815
+#define GL_ALPHA32F_ARB 0x8816
+#define GL_INTENSITY32F_ARB 0x8817
+#define GL_LUMINANCE32F_ARB 0x8818
+#define GL_LUMINANCE_ALPHA32F_ARB 0x8819
+#define GL_RGBA16F_ARB 0x881A
+#define GL_RGB16F_ARB 0x881B
+#define GL_ALPHA16F_ARB 0x881C
+#define GL_INTENSITY16F_ARB 0x881D
+#define GL_LUMINANCE16F_ARB 0x881E
+#define GL_LUMINANCE_ALPHA16F_ARB 0x881F
+#endif
+
+#ifndef GL_ARB_pixel_buffer_object
+#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF
+#endif
+
+#ifndef GL_EXT_abgr
+#define GL_ABGR_EXT 0x8000
+#endif
+
+#ifndef GL_EXT_blend_color
+#define GL_CONSTANT_COLOR_EXT 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002
+#define GL_CONSTANT_ALPHA_EXT 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004
+#define GL_BLEND_COLOR_EXT 0x8005
+#endif
+
+#ifndef GL_EXT_polygon_offset
+#define GL_POLYGON_OFFSET_EXT 0x8037
+#define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038
+#define GL_POLYGON_OFFSET_BIAS_EXT 0x8039
+#endif
+
+#ifndef GL_EXT_texture
+#define GL_ALPHA4_EXT 0x803B
+#define GL_ALPHA8_EXT 0x803C
+#define GL_ALPHA12_EXT 0x803D
+#define GL_ALPHA16_EXT 0x803E
+#define GL_LUMINANCE4_EXT 0x803F
+#define GL_LUMINANCE8_EXT 0x8040
+#define GL_LUMINANCE12_EXT 0x8041
+#define GL_LUMINANCE16_EXT 0x8042
+#define GL_LUMINANCE4_ALPHA4_EXT 0x8043
+#define GL_LUMINANCE6_ALPHA2_EXT 0x8044
+#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
+#define GL_LUMINANCE12_ALPHA4_EXT 0x8046
+#define GL_LUMINANCE12_ALPHA12_EXT 0x8047
+#define GL_LUMINANCE16_ALPHA16_EXT 0x8048
+#define GL_INTENSITY_EXT 0x8049
+#define GL_INTENSITY4_EXT 0x804A
+#define GL_INTENSITY8_EXT 0x804B
+#define GL_INTENSITY12_EXT 0x804C
+#define GL_INTENSITY16_EXT 0x804D
+#define GL_RGB2_EXT 0x804E
+#define GL_RGB4_EXT 0x804F
+#define GL_RGB5_EXT 0x8050
+#define GL_RGB8_EXT 0x8051
+#define GL_RGB10_EXT 0x8052
+#define GL_RGB12_EXT 0x8053
+#define GL_RGB16_EXT 0x8054
+#define GL_RGBA2_EXT 0x8055
+#define GL_RGBA4_EXT 0x8056
+#define GL_RGB5_A1_EXT 0x8057
+#define GL_RGBA8_EXT 0x8058
+#define GL_RGB10_A2_EXT 0x8059
+#define GL_RGBA12_EXT 0x805A
+#define GL_RGBA16_EXT 0x805B
+#define GL_TEXTURE_RED_SIZE_EXT 0x805C
+#define GL_TEXTURE_GREEN_SIZE_EXT 0x805D
+#define GL_TEXTURE_BLUE_SIZE_EXT 0x805E
+#define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F
+#define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060
+#define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061
+#define GL_REPLACE_EXT 0x8062
+#define GL_PROXY_TEXTURE_1D_EXT 0x8063
+#define GL_PROXY_TEXTURE_2D_EXT 0x8064
+#define GL_TEXTURE_TOO_LARGE_EXT 0x8065
+#endif
+
+#ifndef GL_EXT_texture3D
+#define GL_PACK_SKIP_IMAGES_EXT 0x806B
+#define GL_PACK_IMAGE_HEIGHT_EXT 0x806C
+#define GL_UNPACK_SKIP_IMAGES_EXT 0x806D
+#define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E
+#define GL_TEXTURE_3D_EXT 0x806F
+#define GL_PROXY_TEXTURE_3D_EXT 0x8070
+#define GL_TEXTURE_DEPTH_EXT 0x8071
+#define GL_TEXTURE_WRAP_R_EXT 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073
+#endif
+
+#ifndef GL_SGIS_texture_filter4
+#define GL_FILTER4_SGIS 0x8146
+#define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147
+#endif
+
+#ifndef GL_EXT_subtexture
+#endif
+
+#ifndef GL_EXT_copy_texture
+#endif
+
+#ifndef GL_EXT_histogram
+#define GL_HISTOGRAM_EXT 0x8024
+#define GL_PROXY_HISTOGRAM_EXT 0x8025
+#define GL_HISTOGRAM_WIDTH_EXT 0x8026
+#define GL_HISTOGRAM_FORMAT_EXT 0x8027
+#define GL_HISTOGRAM_RED_SIZE_EXT 0x8028
+#define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029
+#define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C
+#define GL_HISTOGRAM_SINK_EXT 0x802D
+#define GL_MINMAX_EXT 0x802E
+#define GL_MINMAX_FORMAT_EXT 0x802F
+#define GL_MINMAX_SINK_EXT 0x8030
+#define GL_TABLE_TOO_LARGE_EXT 0x8031
+#endif
+
+#ifndef GL_EXT_convolution
+#define GL_CONVOLUTION_1D_EXT 0x8010
+#define GL_CONVOLUTION_2D_EXT 0x8011
+#define GL_SEPARABLE_2D_EXT 0x8012
+#define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013
+#define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014
+#define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015
+#define GL_REDUCE_EXT 0x8016
+#define GL_CONVOLUTION_FORMAT_EXT 0x8017
+#define GL_CONVOLUTION_WIDTH_EXT 0x8018
+#define GL_CONVOLUTION_HEIGHT_EXT 0x8019
+#define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023
+#endif
+
+#ifndef GL_SGI_color_matrix
+#define GL_COLOR_MATRIX_SGI 0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB
+#endif
+
+#ifndef GL_SGI_color_table
+#define GL_COLOR_TABLE_SGI 0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2
+#define GL_PROXY_COLOR_TABLE_SGI 0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5
+#define GL_COLOR_TABLE_SCALE_SGI 0x80D6
+#define GL_COLOR_TABLE_BIAS_SGI 0x80D7
+#define GL_COLOR_TABLE_FORMAT_SGI 0x80D8
+#define GL_COLOR_TABLE_WIDTH_SGI 0x80D9
+#define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF
+#endif
+
+#ifndef GL_SGIS_pixel_texture
+#define GL_PIXEL_TEXTURE_SGIS 0x8353
+#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354
+#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355
+#define GL_PIXEL_GROUP_COLOR_SGIS 0x8356
+#endif
+
+#ifndef GL_SGIX_pixel_texture
+#define GL_PIXEL_TEX_GEN_SGIX 0x8139
+#define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B
+#endif
+
+#ifndef GL_SGIS_texture4D
+#define GL_PACK_SKIP_VOLUMES_SGIS 0x8130
+#define GL_PACK_IMAGE_DEPTH_SGIS 0x8131
+#define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132
+#define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133
+#define GL_TEXTURE_4D_SGIS 0x8134
+#define GL_PROXY_TEXTURE_4D_SGIS 0x8135
+#define GL_TEXTURE_4DSIZE_SGIS 0x8136
+#define GL_TEXTURE_WRAP_Q_SGIS 0x8137
+#define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138
+#define GL_TEXTURE_4D_BINDING_SGIS 0x814F
+#endif
+
+#ifndef GL_SGI_texture_color_table
+#define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC
+#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD
+#endif
+
+#ifndef GL_EXT_cmyka
+#define GL_CMYK_EXT 0x800C
+#define GL_CMYKA_EXT 0x800D
+#define GL_PACK_CMYK_HINT_EXT 0x800E
+#define GL_UNPACK_CMYK_HINT_EXT 0x800F
+#endif
+
+#ifndef GL_EXT_texture_object
+#define GL_TEXTURE_PRIORITY_EXT 0x8066
+#define GL_TEXTURE_RESIDENT_EXT 0x8067
+#define GL_TEXTURE_1D_BINDING_EXT 0x8068
+#define GL_TEXTURE_2D_BINDING_EXT 0x8069
+#define GL_TEXTURE_3D_BINDING_EXT 0x806A
+#endif
+
+#ifndef GL_SGIS_detail_texture
+#define GL_DETAIL_TEXTURE_2D_SGIS 0x8095
+#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096
+#define GL_LINEAR_DETAIL_SGIS 0x8097
+#define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098
+#define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099
+#define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A
+#define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B
+#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C
+#endif
+
+#ifndef GL_SGIS_sharpen_texture
+#define GL_LINEAR_SHARPEN_SGIS 0x80AD
+#define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE
+#define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF
+#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0
+#endif
+
+#ifndef GL_EXT_packed_pixels
+#define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034
+#define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035
+#define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036
+#endif
+
+#ifndef GL_SGIS_texture_lod
+#define GL_TEXTURE_MIN_LOD_SGIS 0x813A
+#define GL_TEXTURE_MAX_LOD_SGIS 0x813B
+#define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C
+#define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D
+#endif
+
+#ifndef GL_SGIS_multisample
+#define GL_MULTISAMPLE_SGIS 0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F
+#define GL_SAMPLE_MASK_SGIS 0x80A0
+#define GL_1PASS_SGIS 0x80A1
+#define GL_2PASS_0_SGIS 0x80A2
+#define GL_2PASS_1_SGIS 0x80A3
+#define GL_4PASS_0_SGIS 0x80A4
+#define GL_4PASS_1_SGIS 0x80A5
+#define GL_4PASS_2_SGIS 0x80A6
+#define GL_4PASS_3_SGIS 0x80A7
+#define GL_SAMPLE_BUFFERS_SGIS 0x80A8
+#define GL_SAMPLES_SGIS 0x80A9
+#define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA
+#define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB
+#define GL_SAMPLE_PATTERN_SGIS 0x80AC
+#endif
+
+#ifndef GL_EXT_rescale_normal
+#define GL_RESCALE_NORMAL_EXT 0x803A
+#endif
+
+#ifndef GL_EXT_vertex_array
+#define GL_VERTEX_ARRAY_EXT 0x8074
+#define GL_NORMAL_ARRAY_EXT 0x8075
+#define GL_COLOR_ARRAY_EXT 0x8076
+#define GL_INDEX_ARRAY_EXT 0x8077
+#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078
+#define GL_EDGE_FLAG_ARRAY_EXT 0x8079
+#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A
+#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B
+#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C
+#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D
+#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E
+#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F
+#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080
+#define GL_COLOR_ARRAY_SIZE_EXT 0x8081
+#define GL_COLOR_ARRAY_TYPE_EXT 0x8082
+#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083
+#define GL_COLOR_ARRAY_COUNT_EXT 0x8084
+#define GL_INDEX_ARRAY_TYPE_EXT 0x8085
+#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086
+#define GL_INDEX_ARRAY_COUNT_EXT 0x8087
+#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A
+#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B
+#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C
+#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D
+#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E
+#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F
+#define GL_COLOR_ARRAY_POINTER_EXT 0x8090
+#define GL_INDEX_ARRAY_POINTER_EXT 0x8091
+#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092
+#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093
+#endif
+
+#ifndef GL_EXT_misc_attribute
+#endif
+
+#ifndef GL_SGIS_generate_mipmap
+#define GL_GENERATE_MIPMAP_SGIS 0x8191
+#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
+#endif
+
+#ifndef GL_SGIX_clipmap
+#define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170
+#define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171
+#define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172
+#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173
+#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174
+#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175
+#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176
+#define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177
+#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178
+#define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D
+#define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E
+#define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F
+#endif
+
+#ifndef GL_SGIX_shadow
+#define GL_TEXTURE_COMPARE_SGIX 0x819A
+#define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B
+#define GL_TEXTURE_LEQUAL_R_SGIX 0x819C
+#define GL_TEXTURE_GEQUAL_R_SGIX 0x819D
+#endif
+
+#ifndef GL_SGIS_texture_edge_clamp
+#define GL_CLAMP_TO_EDGE_SGIS 0x812F
+#endif
+
+#ifndef GL_SGIS_texture_border_clamp
+#define GL_CLAMP_TO_BORDER_SGIS 0x812D
+#endif
+
+#ifndef GL_EXT_blend_minmax
+#define GL_FUNC_ADD_EXT 0x8006
+#define GL_MIN_EXT 0x8007
+#define GL_MAX_EXT 0x8008
+#define GL_BLEND_EQUATION_EXT 0x8009
+#endif
+
+#ifndef GL_EXT_blend_subtract
+#define GL_FUNC_SUBTRACT_EXT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B
+#endif
+
+#ifndef GL_EXT_blend_logic_op
+#endif
+
+#ifndef GL_SGIX_interlace
+#define GL_INTERLACE_SGIX 0x8094
+#endif
+
+#ifndef GL_SGIX_pixel_tiles
+#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E
+#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F
+#define GL_PIXEL_TILE_WIDTH_SGIX 0x8140
+#define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141
+#define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142
+#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143
+#define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144
+#define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145
+#endif
+
+#ifndef GL_SGIS_texture_select
+#define GL_DUAL_ALPHA4_SGIS 0x8110
+#define GL_DUAL_ALPHA8_SGIS 0x8111
+#define GL_DUAL_ALPHA12_SGIS 0x8112
+#define GL_DUAL_ALPHA16_SGIS 0x8113
+#define GL_DUAL_LUMINANCE4_SGIS 0x8114
+#define GL_DUAL_LUMINANCE8_SGIS 0x8115
+#define GL_DUAL_LUMINANCE12_SGIS 0x8116
+#define GL_DUAL_LUMINANCE16_SGIS 0x8117
+#define GL_DUAL_INTENSITY4_SGIS 0x8118
+#define GL_DUAL_INTENSITY8_SGIS 0x8119
+#define GL_DUAL_INTENSITY12_SGIS 0x811A
+#define GL_DUAL_INTENSITY16_SGIS 0x811B
+#define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C
+#define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D
+#define GL_QUAD_ALPHA4_SGIS 0x811E
+#define GL_QUAD_ALPHA8_SGIS 0x811F
+#define GL_QUAD_LUMINANCE4_SGIS 0x8120
+#define GL_QUAD_LUMINANCE8_SGIS 0x8121
+#define GL_QUAD_INTENSITY4_SGIS 0x8122
+#define GL_QUAD_INTENSITY8_SGIS 0x8123
+#define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124
+#define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125
+#endif
+
+#ifndef GL_SGIX_sprite
+#define GL_SPRITE_SGIX 0x8148
+#define GL_SPRITE_MODE_SGIX 0x8149
+#define GL_SPRITE_AXIS_SGIX 0x814A
+#define GL_SPRITE_TRANSLATION_SGIX 0x814B
+#define GL_SPRITE_AXIAL_SGIX 0x814C
+#define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D
+#define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E
+#endif
+
+#ifndef GL_SGIX_texture_multi_buffer
+#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E
+#endif
+
+#ifndef GL_EXT_point_parameters
+#define GL_POINT_SIZE_MIN_EXT 0x8126
+#define GL_POINT_SIZE_MAX_EXT 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128
+#define GL_DISTANCE_ATTENUATION_EXT 0x8129
+#endif
+
+#ifndef GL_SGIS_point_parameters
+#define GL_POINT_SIZE_MIN_SGIS 0x8126
+#define GL_POINT_SIZE_MAX_SGIS 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128
+#define GL_DISTANCE_ATTENUATION_SGIS 0x8129
+#endif
+
+#ifndef GL_SGIX_instruments
+#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180
+#define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181
+#endif
+
+#ifndef GL_SGIX_texture_scale_bias
+#define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179
+#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A
+#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B
+#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C
+#endif
+
+#ifndef GL_SGIX_framezoom
+#define GL_FRAMEZOOM_SGIX 0x818B
+#define GL_FRAMEZOOM_FACTOR_SGIX 0x818C
+#define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D
+#endif
+
+#ifndef GL_SGIX_tag_sample_buffer
+#endif
+
+#ifndef GL_FfdMaskSGIX
+#define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001
+#define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002
+#endif
+
+#ifndef GL_SGIX_polynomial_ffd
+#define GL_GEOMETRY_DEFORMATION_SGIX 0x8194
+#define GL_TEXTURE_DEFORMATION_SGIX 0x8195
+#define GL_DEFORMATIONS_MASK_SGIX 0x8196
+#define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197
+#endif
+
+#ifndef GL_SGIX_reference_plane
+#define GL_REFERENCE_PLANE_SGIX 0x817D
+#define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E
+#endif
+
+#ifndef GL_SGIX_flush_raster
+#endif
+
+#ifndef GL_SGIX_depth_texture
+#define GL_DEPTH_COMPONENT16_SGIX 0x81A5
+#define GL_DEPTH_COMPONENT24_SGIX 0x81A6
+#define GL_DEPTH_COMPONENT32_SGIX 0x81A7
+#endif
+
+#ifndef GL_SGIS_fog_function
+#define GL_FOG_FUNC_SGIS 0x812A
+#define GL_FOG_FUNC_POINTS_SGIS 0x812B
+#define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C
+#endif
+
+#ifndef GL_SGIX_fog_offset
+#define GL_FOG_OFFSET_SGIX 0x8198
+#define GL_FOG_OFFSET_VALUE_SGIX 0x8199
+#endif
+
+#ifndef GL_HP_image_transform
+#define GL_IMAGE_SCALE_X_HP 0x8155
+#define GL_IMAGE_SCALE_Y_HP 0x8156
+#define GL_IMAGE_TRANSLATE_X_HP 0x8157
+#define GL_IMAGE_TRANSLATE_Y_HP 0x8158
+#define GL_IMAGE_ROTATE_ANGLE_HP 0x8159
+#define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A
+#define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B
+#define GL_IMAGE_MAG_FILTER_HP 0x815C
+#define GL_IMAGE_MIN_FILTER_HP 0x815D
+#define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E
+#define GL_CUBIC_HP 0x815F
+#define GL_AVERAGE_HP 0x8160
+#define GL_IMAGE_TRANSFORM_2D_HP 0x8161
+#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162
+#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163
+#endif
+
+#ifndef GL_HP_convolution_border_modes
+#define GL_IGNORE_BORDER_HP 0x8150
+#define GL_CONSTANT_BORDER_HP 0x8151
+#define GL_REPLICATE_BORDER_HP 0x8153
+#define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154
+#endif
+
+#ifndef GL_INGR_palette_buffer
+#endif
+
+#ifndef GL_SGIX_texture_add_env
+#define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE
+#endif
+
+#ifndef GL_EXT_color_subtable
+#endif
+
+#ifndef GL_PGI_vertex_hints
+#define GL_VERTEX_DATA_HINT_PGI 0x1A22A
+#define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B
+#define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C
+#define GL_MAX_VERTEX_HINT_PGI 0x1A22D
+#define GL_COLOR3_BIT_PGI 0x00010000
+#define GL_COLOR4_BIT_PGI 0x00020000
+#define GL_EDGEFLAG_BIT_PGI 0x00040000
+#define GL_INDEX_BIT_PGI 0x00080000
+#define GL_MAT_AMBIENT_BIT_PGI 0x00100000
+#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000
+#define GL_MAT_DIFFUSE_BIT_PGI 0x00400000
+#define GL_MAT_EMISSION_BIT_PGI 0x00800000
+#define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000
+#define GL_MAT_SHININESS_BIT_PGI 0x02000000
+#define GL_MAT_SPECULAR_BIT_PGI 0x04000000
+#define GL_NORMAL_BIT_PGI 0x08000000
+#define GL_TEXCOORD1_BIT_PGI 0x10000000
+#define GL_TEXCOORD2_BIT_PGI 0x20000000
+#define GL_TEXCOORD3_BIT_PGI 0x40000000
+#define GL_TEXCOORD4_BIT_PGI 0x80000000
+#define GL_VERTEX23_BIT_PGI 0x00000004
+#define GL_VERTEX4_BIT_PGI 0x00000008
+#endif
+
+#ifndef GL_PGI_misc_hints
+#define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8
+#define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD
+#define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE
+#define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202
+#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203
+#define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204
+#define GL_ALWAYS_FAST_HINT_PGI 0x1A20C
+#define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D
+#define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E
+#define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F
+#define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210
+#define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211
+#define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216
+#define GL_STRICT_LIGHTING_HINT_PGI 0x1A217
+#define GL_STRICT_SCISSOR_HINT_PGI 0x1A218
+#define GL_FULL_STIPPLE_HINT_PGI 0x1A219
+#define GL_CLIP_NEAR_HINT_PGI 0x1A220
+#define GL_CLIP_FAR_HINT_PGI 0x1A221
+#define GL_WIDE_LINE_HINT_PGI 0x1A222
+#define GL_BACK_NORMALS_HINT_PGI 0x1A223
+#endif
+
+#ifndef GL_EXT_paletted_texture
+#define GL_COLOR_INDEX1_EXT 0x80E2
+#define GL_COLOR_INDEX2_EXT 0x80E3
+#define GL_COLOR_INDEX4_EXT 0x80E4
+#define GL_COLOR_INDEX8_EXT 0x80E5
+#define GL_COLOR_INDEX12_EXT 0x80E6
+#define GL_COLOR_INDEX16_EXT 0x80E7
+#define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED
+#endif
+
+#ifndef GL_EXT_clip_volume_hint
+#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0
+#endif
+
+#ifndef GL_SGIX_list_priority
+#define GL_LIST_PRIORITY_SGIX 0x8182
+#endif
+
+#ifndef GL_SGIX_ir_instrument1
+#define GL_IR_INSTRUMENT1_SGIX 0x817F
+#endif
+
+#ifndef GL_SGIX_calligraphic_fragment
+#define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183
+#endif
+
+#ifndef GL_SGIX_texture_lod_bias
+#define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E
+#define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F
+#define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190
+#endif
+
+#ifndef GL_SGIX_shadow_ambient
+#define GL_SHADOW_AMBIENT_SGIX 0x80BF
+#endif
+
+#ifndef GL_EXT_index_texture
+#endif
+
+#ifndef GL_EXT_index_material
+#define GL_INDEX_MATERIAL_EXT 0x81B8
+#define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9
+#define GL_INDEX_MATERIAL_FACE_EXT 0x81BA
+#endif
+
+#ifndef GL_EXT_index_func
+#define GL_INDEX_TEST_EXT 0x81B5
+#define GL_INDEX_TEST_FUNC_EXT 0x81B6
+#define GL_INDEX_TEST_REF_EXT 0x81B7
+#endif
+
+#ifndef GL_EXT_index_array_formats
+#define GL_IUI_V2F_EXT 0x81AD
+#define GL_IUI_V3F_EXT 0x81AE
+#define GL_IUI_N3F_V2F_EXT 0x81AF
+#define GL_IUI_N3F_V3F_EXT 0x81B0
+#define GL_T2F_IUI_V2F_EXT 0x81B1
+#define GL_T2F_IUI_V3F_EXT 0x81B2
+#define GL_T2F_IUI_N3F_V2F_EXT 0x81B3
+#define GL_T2F_IUI_N3F_V3F_EXT 0x81B4
+#endif
+
+#ifndef GL_EXT_compiled_vertex_array
+#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8
+#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9
+#endif
+
+#ifndef GL_EXT_cull_vertex
+#define GL_CULL_VERTEX_EXT 0x81AA
+#define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB
+#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC
+#endif
+
+#ifndef GL_SGIX_ycrcb
+#define GL_YCRCB_422_SGIX 0x81BB
+#define GL_YCRCB_444_SGIX 0x81BC
+#endif
+
+#ifndef GL_SGIX_fragment_lighting
+#define GL_FRAGMENT_LIGHTING_SGIX 0x8400
+#define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401
+#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402
+#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403
+#define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404
+#define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405
+#define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406
+#define GL_LIGHT_ENV_MODE_SGIX 0x8407
+#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408
+#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409
+#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A
+#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B
+#define GL_FRAGMENT_LIGHT0_SGIX 0x840C
+#define GL_FRAGMENT_LIGHT1_SGIX 0x840D
+#define GL_FRAGMENT_LIGHT2_SGIX 0x840E
+#define GL_FRAGMENT_LIGHT3_SGIX 0x840F
+#define GL_FRAGMENT_LIGHT4_SGIX 0x8410
+#define GL_FRAGMENT_LIGHT5_SGIX 0x8411
+#define GL_FRAGMENT_LIGHT6_SGIX 0x8412
+#define GL_FRAGMENT_LIGHT7_SGIX 0x8413
+#endif
+
+#ifndef GL_IBM_rasterpos_clip
+#define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262
+#endif
+
+#ifndef GL_HP_texture_lighting
+#define GL_TEXTURE_LIGHTING_MODE_HP 0x8167
+#define GL_TEXTURE_POST_SPECULAR_HP 0x8168
+#define GL_TEXTURE_PRE_SPECULAR_HP 0x8169
+#endif
+
+#ifndef GL_EXT_draw_range_elements
+#define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8
+#define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9
+#endif
+
+#ifndef GL_WIN_phong_shading
+#define GL_PHONG_WIN 0x80EA
+#define GL_PHONG_HINT_WIN 0x80EB
+#endif
+
+#ifndef GL_WIN_specular_fog
+#define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC
+#endif
+
+#ifndef GL_EXT_light_texture
+#define GL_FRAGMENT_MATERIAL_EXT 0x8349
+#define GL_FRAGMENT_NORMAL_EXT 0x834A
+#define GL_FRAGMENT_COLOR_EXT 0x834C
+#define GL_ATTENUATION_EXT 0x834D
+#define GL_SHADOW_ATTENUATION_EXT 0x834E
+#define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F
+#define GL_TEXTURE_LIGHT_EXT 0x8350
+#define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351
+#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352
+/* reuse GL_FRAGMENT_DEPTH_EXT */
+#endif
+
+#ifndef GL_SGIX_blend_alpha_minmax
+#define GL_ALPHA_MIN_SGIX 0x8320
+#define GL_ALPHA_MAX_SGIX 0x8321
+#endif
+
+#ifndef GL_SGIX_impact_pixel_texture
+#define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX 0x8184
+#define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX 0x8185
+#define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX 0x8186
+#define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187
+#define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188
+#define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX 0x8189
+#define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX 0x818A
+#endif
+
+#ifndef GL_EXT_bgra
+#define GL_BGR_EXT 0x80E0
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+#ifndef GL_SGIX_async
+#define GL_ASYNC_MARKER_SGIX 0x8329
+#endif
+
+#ifndef GL_SGIX_async_pixel
+#define GL_ASYNC_TEX_IMAGE_SGIX 0x835C
+#define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D
+#define GL_ASYNC_READ_PIXELS_SGIX 0x835E
+#define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F
+#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360
+#define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361
+#endif
+
+#ifndef GL_SGIX_async_histogram
+#define GL_ASYNC_HISTOGRAM_SGIX 0x832C
+#define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D
+#endif
+
+#ifndef GL_INTEL_texture_scissor
+#endif
+
+#ifndef GL_INTEL_parallel_arrays
+#define GL_PARALLEL_ARRAYS_INTEL 0x83F4
+#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5
+#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6
+#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7
+#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8
+#endif
+
+#ifndef GL_HP_occlusion_test
+#define GL_OCCLUSION_TEST_HP 0x8165
+#define GL_OCCLUSION_TEST_RESULT_HP 0x8166
+#endif
+
+#ifndef GL_EXT_pixel_transform
+#define GL_PIXEL_TRANSFORM_2D_EXT 0x8330
+#define GL_PIXEL_MAG_FILTER_EXT 0x8331
+#define GL_PIXEL_MIN_FILTER_EXT 0x8332
+#define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333
+#define GL_CUBIC_EXT 0x8334
+#define GL_AVERAGE_EXT 0x8335
+#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336
+#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337
+#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338
+#endif
+
+#ifndef GL_EXT_pixel_transform_color_table
+#endif
+
+#ifndef GL_EXT_shared_texture_palette
+#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB
+#endif
+
+#ifndef GL_EXT_separate_specular_color
+#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8
+#define GL_SINGLE_COLOR_EXT 0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA
+#endif
+
+#ifndef GL_EXT_secondary_color
+#define GL_COLOR_SUM_EXT 0x8458
+#define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D
+#define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E
+#endif
+
+#ifndef GL_EXT_texture_perturb_normal
+#define GL_PERTURB_EXT 0x85AE
+#define GL_TEXTURE_NORMAL_EXT 0x85AF
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#endif
+
+#ifndef GL_EXT_fog_coord
+#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450
+#define GL_FOG_COORDINATE_EXT 0x8451
+#define GL_FRAGMENT_DEPTH_EXT 0x8452
+#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456
+#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457
+#endif
+
+#ifndef GL_REND_screen_coordinates
+#define GL_SCREEN_COORDINATES_REND 0x8490
+#define GL_INVERTED_SCREEN_W_REND 0x8491
+#endif
+
+#ifndef GL_EXT_coordinate_frame
+#define GL_TANGENT_ARRAY_EXT 0x8439
+#define GL_BINORMAL_ARRAY_EXT 0x843A
+#define GL_CURRENT_TANGENT_EXT 0x843B
+#define GL_CURRENT_BINORMAL_EXT 0x843C
+#define GL_TANGENT_ARRAY_TYPE_EXT 0x843E
+#define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F
+#define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440
+#define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441
+#define GL_TANGENT_ARRAY_POINTER_EXT 0x8442
+#define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443
+#define GL_MAP1_TANGENT_EXT 0x8444
+#define GL_MAP2_TANGENT_EXT 0x8445
+#define GL_MAP1_BINORMAL_EXT 0x8446
+#define GL_MAP2_BINORMAL_EXT 0x8447
+#endif
+
+#ifndef GL_EXT_texture_env_combine
+#define GL_COMBINE_EXT 0x8570
+#define GL_COMBINE_RGB_EXT 0x8571
+#define GL_COMBINE_ALPHA_EXT 0x8572
+#define GL_RGB_SCALE_EXT 0x8573
+#define GL_ADD_SIGNED_EXT 0x8574
+#define GL_INTERPOLATE_EXT 0x8575
+#define GL_CONSTANT_EXT 0x8576
+#define GL_PRIMARY_COLOR_EXT 0x8577
+#define GL_PREVIOUS_EXT 0x8578
+#define GL_SOURCE0_RGB_EXT 0x8580
+#define GL_SOURCE1_RGB_EXT 0x8581
+#define GL_SOURCE2_RGB_EXT 0x8582
+#define GL_SOURCE0_ALPHA_EXT 0x8588
+#define GL_SOURCE1_ALPHA_EXT 0x8589
+#define GL_SOURCE2_ALPHA_EXT 0x858A
+#define GL_OPERAND0_RGB_EXT 0x8590
+#define GL_OPERAND1_RGB_EXT 0x8591
+#define GL_OPERAND2_RGB_EXT 0x8592
+#define GL_OPERAND0_ALPHA_EXT 0x8598
+#define GL_OPERAND1_ALPHA_EXT 0x8599
+#define GL_OPERAND2_ALPHA_EXT 0x859A
+#endif
+
+#ifndef GL_APPLE_specular_vector
+#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0
+#endif
+
+#ifndef GL_APPLE_transform_hint
+#define GL_TRANSFORM_HINT_APPLE 0x85B1
+#endif
+
+#ifndef GL_SGIX_fog_scale
+#define GL_FOG_SCALE_SGIX 0x81FC
+#define GL_FOG_SCALE_VALUE_SGIX 0x81FD
+#endif
+
+#ifndef GL_SUNX_constant_data
+#define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5
+#define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6
+#endif
+
+#ifndef GL_SUN_global_alpha
+#define GL_GLOBAL_ALPHA_SUN 0x81D9
+#define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA
+#endif
+
+#ifndef GL_SUN_triangle_list
+#define GL_RESTART_SUN 0x0001
+#define GL_REPLACE_MIDDLE_SUN 0x0002
+#define GL_REPLACE_OLDEST_SUN 0x0003
+#define GL_TRIANGLE_LIST_SUN 0x81D7
+#define GL_REPLACEMENT_CODE_SUN 0x81D8
+#define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0
+#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1
+#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2
+#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3
+#define GL_R1UI_V3F_SUN 0x85C4
+#define GL_R1UI_C4UB_V3F_SUN 0x85C5
+#define GL_R1UI_C3F_V3F_SUN 0x85C6
+#define GL_R1UI_N3F_V3F_SUN 0x85C7
+#define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8
+#define GL_R1UI_T2F_V3F_SUN 0x85C9
+#define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA
+#define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB
+#endif
+
+#ifndef GL_SUN_vertex
+#endif
+
+#ifndef GL_EXT_blend_func_separate
+#define GL_BLEND_DST_RGB_EXT 0x80C8
+#define GL_BLEND_SRC_RGB_EXT 0x80C9
+#define GL_BLEND_DST_ALPHA_EXT 0x80CA
+#define GL_BLEND_SRC_ALPHA_EXT 0x80CB
+#endif
+
+#ifndef GL_INGR_color_clamp
+#define GL_RED_MIN_CLAMP_INGR 0x8560
+#define GL_GREEN_MIN_CLAMP_INGR 0x8561
+#define GL_BLUE_MIN_CLAMP_INGR 0x8562
+#define GL_ALPHA_MIN_CLAMP_INGR 0x8563
+#define GL_RED_MAX_CLAMP_INGR 0x8564
+#define GL_GREEN_MAX_CLAMP_INGR 0x8565
+#define GL_BLUE_MAX_CLAMP_INGR 0x8566
+#define GL_ALPHA_MAX_CLAMP_INGR 0x8567
+#endif
+
+#ifndef GL_INGR_interlace_read
+#define GL_INTERLACE_READ_INGR 0x8568
+#endif
+
+#ifndef GL_EXT_stencil_wrap
+#define GL_INCR_WRAP_EXT 0x8507
+#define GL_DECR_WRAP_EXT 0x8508
+#endif
+
+#ifndef GL_EXT_422_pixels
+#define GL_422_EXT 0x80CC
+#define GL_422_REV_EXT 0x80CD
+#define GL_422_AVERAGE_EXT 0x80CE
+#define GL_422_REV_AVERAGE_EXT 0x80CF
+#endif
+
+#ifndef GL_NV_texgen_reflection
+#define GL_NORMAL_MAP_NV 0x8511
+#define GL_REFLECTION_MAP_NV 0x8512
+#endif
+
+#ifndef GL_EXT_texture_cube_map
+#define GL_NORMAL_MAP_EXT 0x8511
+#define GL_REFLECTION_MAP_EXT 0x8512
+#define GL_TEXTURE_CUBE_MAP_EXT 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C
+#endif
+
+#ifndef GL_SUN_convolution_border_modes
+#define GL_WRAP_BORDER_SUN 0x81D4
+#endif
+
+#ifndef GL_EXT_texture_env_add
+#endif
+
+#ifndef GL_EXT_texture_lod_bias
+#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD
+#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500
+#define GL_TEXTURE_LOD_BIAS_EXT 0x8501
+#endif
+
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+#ifndef GL_EXT_vertex_weighting
+#define GL_MODELVIEW0_STACK_DEPTH_EXT GL_MODELVIEW_STACK_DEPTH
+#define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502
+#define GL_MODELVIEW0_MATRIX_EXT GL_MODELVIEW_MATRIX
+#define GL_MODELVIEW1_MATRIX_EXT 0x8506
+#define GL_VERTEX_WEIGHTING_EXT 0x8509
+#define GL_MODELVIEW0_EXT GL_MODELVIEW
+#define GL_MODELVIEW1_EXT 0x850A
+#define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B
+#define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C
+#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D
+#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E
+#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F
+#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510
+#endif
+
+#ifndef GL_NV_light_max_exponent
+#define GL_MAX_SHININESS_NV 0x8504
+#define GL_MAX_SPOT_EXPONENT_NV 0x8505
+#endif
+
+#ifndef GL_NV_vertex_array_range
+#define GL_VERTEX_ARRAY_RANGE_NV 0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E
+#define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F
+#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520
+#define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521
+#endif
+
+#ifndef GL_NV_register_combiners
+#define GL_REGISTER_COMBINERS_NV 0x8522
+#define GL_VARIABLE_A_NV 0x8523
+#define GL_VARIABLE_B_NV 0x8524
+#define GL_VARIABLE_C_NV 0x8525
+#define GL_VARIABLE_D_NV 0x8526
+#define GL_VARIABLE_E_NV 0x8527
+#define GL_VARIABLE_F_NV 0x8528
+#define GL_VARIABLE_G_NV 0x8529
+#define GL_CONSTANT_COLOR0_NV 0x852A
+#define GL_CONSTANT_COLOR1_NV 0x852B
+#define GL_PRIMARY_COLOR_NV 0x852C
+#define GL_SECONDARY_COLOR_NV 0x852D
+#define GL_SPARE0_NV 0x852E
+#define GL_SPARE1_NV 0x852F
+#define GL_DISCARD_NV 0x8530
+#define GL_E_TIMES_F_NV 0x8531
+#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532
+#define GL_UNSIGNED_IDENTITY_NV 0x8536
+#define GL_UNSIGNED_INVERT_NV 0x8537
+#define GL_EXPAND_NORMAL_NV 0x8538
+#define GL_EXPAND_NEGATE_NV 0x8539
+#define GL_HALF_BIAS_NORMAL_NV 0x853A
+#define GL_HALF_BIAS_NEGATE_NV 0x853B
+#define GL_SIGNED_IDENTITY_NV 0x853C
+#define GL_SIGNED_NEGATE_NV 0x853D
+#define GL_SCALE_BY_TWO_NV 0x853E
+#define GL_SCALE_BY_FOUR_NV 0x853F
+#define GL_SCALE_BY_ONE_HALF_NV 0x8540
+#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541
+#define GL_COMBINER_INPUT_NV 0x8542
+#define GL_COMBINER_MAPPING_NV 0x8543
+#define GL_COMBINER_COMPONENT_USAGE_NV 0x8544
+#define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545
+#define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546
+#define GL_COMBINER_MUX_SUM_NV 0x8547
+#define GL_COMBINER_SCALE_NV 0x8548
+#define GL_COMBINER_BIAS_NV 0x8549
+#define GL_COMBINER_AB_OUTPUT_NV 0x854A
+#define GL_COMBINER_CD_OUTPUT_NV 0x854B
+#define GL_COMBINER_SUM_OUTPUT_NV 0x854C
+#define GL_MAX_GENERAL_COMBINERS_NV 0x854D
+#define GL_NUM_GENERAL_COMBINERS_NV 0x854E
+#define GL_COLOR_SUM_CLAMP_NV 0x854F
+#define GL_COMBINER0_NV 0x8550
+#define GL_COMBINER1_NV 0x8551
+#define GL_COMBINER2_NV 0x8552
+#define GL_COMBINER3_NV 0x8553
+#define GL_COMBINER4_NV 0x8554
+#define GL_COMBINER5_NV 0x8555
+#define GL_COMBINER6_NV 0x8556
+#define GL_COMBINER7_NV 0x8557
+/* reuse GL_TEXTURE0_ARB */
+/* reuse GL_TEXTURE1_ARB */
+/* reuse GL_ZERO */
+/* reuse GL_NONE */
+/* reuse GL_FOG */
+#endif
+
+#ifndef GL_NV_fog_distance
+#define GL_FOG_DISTANCE_MODE_NV 0x855A
+#define GL_EYE_RADIAL_NV 0x855B
+#define GL_EYE_PLANE_ABSOLUTE_NV 0x855C
+/* reuse GL_EYE_PLANE */
+#endif
+
+#ifndef GL_NV_texgen_emboss
+#define GL_EMBOSS_LIGHT_NV 0x855D
+#define GL_EMBOSS_CONSTANT_NV 0x855E
+#define GL_EMBOSS_MAP_NV 0x855F
+#endif
+
+#ifndef GL_NV_blend_square
+#endif
+
+#ifndef GL_NV_texture_env_combine4
+#define GL_COMBINE4_NV 0x8503
+#define GL_SOURCE3_RGB_NV 0x8583
+#define GL_SOURCE3_ALPHA_NV 0x858B
+#define GL_OPERAND3_RGB_NV 0x8593
+#define GL_OPERAND3_ALPHA_NV 0x859B
+#endif
+
+#ifndef GL_MESA_resize_buffers
+#endif
+
+#ifndef GL_MESA_window_pos
+#endif
+
+#ifndef GL_EXT_texture_compression_s3tc
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+#endif
+
+#ifndef GL_IBM_cull_vertex
+#define GL_CULL_VERTEX_IBM 103050
+#endif
+
+#ifndef GL_IBM_multimode_draw_arrays
+#endif
+
+#ifndef GL_IBM_vertex_array_lists
+#define GL_VERTEX_ARRAY_LIST_IBM 103070
+#define GL_NORMAL_ARRAY_LIST_IBM 103071
+#define GL_COLOR_ARRAY_LIST_IBM 103072
+#define GL_INDEX_ARRAY_LIST_IBM 103073
+#define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074
+#define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075
+#define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076
+#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077
+#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080
+#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081
+#define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082
+#define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083
+#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084
+#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085
+#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086
+#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087
+#endif
+
+#ifndef GL_SGIX_subsample
+#define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0
+#define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1
+#define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2
+#define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3
+#define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4
+#endif
+
+#ifndef GL_SGIX_ycrcb_subsample
+#endif
+
+#ifndef GL_SGIX_ycrcba
+#define GL_YCRCB_SGIX 0x8318
+#define GL_YCRCBA_SGIX 0x8319
+#endif
+
+#ifndef GL_SGI_depth_pass_instrument
+#define GL_DEPTH_PASS_INSTRUMENT_SGIX 0x8310
+#define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311
+#define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312
+#endif
+
+#ifndef GL_3DFX_texture_compression_FXT1
+#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
+#define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1
+#endif
+
+#ifndef GL_3DFX_multisample
+#define GL_MULTISAMPLE_3DFX 0x86B2
+#define GL_SAMPLE_BUFFERS_3DFX 0x86B3
+#define GL_SAMPLES_3DFX 0x86B4
+#define GL_MULTISAMPLE_BIT_3DFX 0x20000000
+#endif
+
+#ifndef GL_3DFX_tbuffer
+#endif
+
+#ifndef GL_EXT_multisample
+#define GL_MULTISAMPLE_EXT 0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F
+#define GL_SAMPLE_MASK_EXT 0x80A0
+#define GL_1PASS_EXT 0x80A1
+#define GL_2PASS_0_EXT 0x80A2
+#define GL_2PASS_1_EXT 0x80A3
+#define GL_4PASS_0_EXT 0x80A4
+#define GL_4PASS_1_EXT 0x80A5
+#define GL_4PASS_2_EXT 0x80A6
+#define GL_4PASS_3_EXT 0x80A7
+#define GL_SAMPLE_BUFFERS_EXT 0x80A8
+#define GL_SAMPLES_EXT 0x80A9
+#define GL_SAMPLE_MASK_VALUE_EXT 0x80AA
+#define GL_SAMPLE_MASK_INVERT_EXT 0x80AB
+#define GL_SAMPLE_PATTERN_EXT 0x80AC
+#define GL_MULTISAMPLE_BIT_EXT 0x20000000
+#endif
+
+#ifndef GL_SGIX_vertex_preclip
+#define GL_VERTEX_PRECLIP_SGIX 0x83EE
+#define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF
+#endif
+
+#ifndef GL_SGIX_convolution_accuracy
+#define GL_CONVOLUTION_HINT_SGIX 0x8316
+#endif
+
+#ifndef GL_SGIX_resample
+#define GL_PACK_RESAMPLE_SGIX 0x842C
+#define GL_UNPACK_RESAMPLE_SGIX 0x842D
+#define GL_RESAMPLE_REPLICATE_SGIX 0x842E
+#define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F
+#define GL_RESAMPLE_DECIMATE_SGIX 0x8430
+#endif
+
+#ifndef GL_SGIS_point_line_texgen
+#define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0
+#define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1
+#define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2
+#define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3
+#define GL_EYE_POINT_SGIS 0x81F4
+#define GL_OBJECT_POINT_SGIS 0x81F5
+#define GL_EYE_LINE_SGIS 0x81F6
+#define GL_OBJECT_LINE_SGIS 0x81F7
+#endif
+
+#ifndef GL_SGIS_texture_color_mask
+#define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF
+#endif
+
+#ifndef GL_EXT_texture_env_dot3
+#define GL_DOT3_RGB_EXT 0x8740
+#define GL_DOT3_RGBA_EXT 0x8741
+#endif
+
+#ifndef GL_ATI_texture_mirror_once
+#define GL_MIRROR_CLAMP_ATI 0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743
+#endif
+
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+#endif
+
+#ifndef GL_IBM_texture_mirrored_repeat
+#define GL_MIRRORED_REPEAT_IBM 0x8370
+#endif
+
+#ifndef GL_NV_evaluators
+#define GL_EVAL_2D_NV 0x86C0
+#define GL_EVAL_TRIANGULAR_2D_NV 0x86C1
+#define GL_MAP_TESSELLATION_NV 0x86C2
+#define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3
+#define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4
+#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5
+#define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6
+#define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7
+#define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8
+#define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9
+#define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA
+#define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB
+#define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC
+#define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD
+#define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE
+#define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF
+#define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0
+#define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1
+#define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2
+#define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3
+#define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4
+#define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5
+#define GL_MAX_MAP_TESSELLATION_NV 0x86D6
+#define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7
+#endif
+
+#ifndef GL_NV_packed_depth_stencil
+#define GL_DEPTH_STENCIL_NV 0x84F9
+#define GL_UNSIGNED_INT_24_8_NV 0x84FA
+#endif
+
+#ifndef GL_NV_register_combiners2
+#define GL_PER_STAGE_CONSTANTS_NV 0x8535
+#endif
+
+#ifndef GL_NV_texture_compression_vtc
+#endif
+
+#ifndef GL_NV_texture_rectangle
+#define GL_TEXTURE_RECTANGLE_NV 0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8
+#endif
+
+#ifndef GL_NV_texture_shader
+#define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C
+#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D
+#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E
+#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9
+#define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA
+#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB
+#define GL_DSDT_MAG_INTENSITY_NV 0x86DC
+#define GL_SHADER_CONSISTENT_NV 0x86DD
+#define GL_TEXTURE_SHADER_NV 0x86DE
+#define GL_SHADER_OPERATION_NV 0x86DF
+#define GL_CULL_MODES_NV 0x86E0
+#define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1
+#define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2
+#define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3
+#define GL_OFFSET_TEXTURE_2D_MATRIX_NV GL_OFFSET_TEXTURE_MATRIX_NV
+#define GL_OFFSET_TEXTURE_2D_SCALE_NV GL_OFFSET_TEXTURE_SCALE_NV
+#define GL_OFFSET_TEXTURE_2D_BIAS_NV GL_OFFSET_TEXTURE_BIAS_NV
+#define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4
+#define GL_CONST_EYE_NV 0x86E5
+#define GL_PASS_THROUGH_NV 0x86E6
+#define GL_CULL_FRAGMENT_NV 0x86E7
+#define GL_OFFSET_TEXTURE_2D_NV 0x86E8
+#define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9
+#define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA
+#define GL_DOT_PRODUCT_NV 0x86EC
+#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED
+#define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE
+#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0
+#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1
+#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2
+#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3
+#define GL_HILO_NV 0x86F4
+#define GL_DSDT_NV 0x86F5
+#define GL_DSDT_MAG_NV 0x86F6
+#define GL_DSDT_MAG_VIB_NV 0x86F7
+#define GL_HILO16_NV 0x86F8
+#define GL_SIGNED_HILO_NV 0x86F9
+#define GL_SIGNED_HILO16_NV 0x86FA
+#define GL_SIGNED_RGBA_NV 0x86FB
+#define GL_SIGNED_RGBA8_NV 0x86FC
+#define GL_SIGNED_RGB_NV 0x86FE
+#define GL_SIGNED_RGB8_NV 0x86FF
+#define GL_SIGNED_LUMINANCE_NV 0x8701
+#define GL_SIGNED_LUMINANCE8_NV 0x8702
+#define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703
+#define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704
+#define GL_SIGNED_ALPHA_NV 0x8705
+#define GL_SIGNED_ALPHA8_NV 0x8706
+#define GL_SIGNED_INTENSITY_NV 0x8707
+#define GL_SIGNED_INTENSITY8_NV 0x8708
+#define GL_DSDT8_NV 0x8709
+#define GL_DSDT8_MAG8_NV 0x870A
+#define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B
+#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C
+#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D
+#define GL_HI_SCALE_NV 0x870E
+#define GL_LO_SCALE_NV 0x870F
+#define GL_DS_SCALE_NV 0x8710
+#define GL_DT_SCALE_NV 0x8711
+#define GL_MAGNITUDE_SCALE_NV 0x8712
+#define GL_VIBRANCE_SCALE_NV 0x8713
+#define GL_HI_BIAS_NV 0x8714
+#define GL_LO_BIAS_NV 0x8715
+#define GL_DS_BIAS_NV 0x8716
+#define GL_DT_BIAS_NV 0x8717
+#define GL_MAGNITUDE_BIAS_NV 0x8718
+#define GL_VIBRANCE_BIAS_NV 0x8719
+#define GL_TEXTURE_BORDER_VALUES_NV 0x871A
+#define GL_TEXTURE_HI_SIZE_NV 0x871B
+#define GL_TEXTURE_LO_SIZE_NV 0x871C
+#define GL_TEXTURE_DS_SIZE_NV 0x871D
+#define GL_TEXTURE_DT_SIZE_NV 0x871E
+#define GL_TEXTURE_MAG_SIZE_NV 0x871F
+#endif
+
+#ifndef GL_NV_texture_shader2
+#define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF
+#endif
+
+#ifndef GL_NV_vertex_array_range2
+#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533
+#endif
+
+#ifndef GL_NV_vertex_program
+#define GL_VERTEX_PROGRAM_NV 0x8620
+#define GL_VERTEX_STATE_PROGRAM_NV 0x8621
+#define GL_ATTRIB_ARRAY_SIZE_NV 0x8623
+#define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624
+#define GL_ATTRIB_ARRAY_TYPE_NV 0x8625
+#define GL_CURRENT_ATTRIB_NV 0x8626
+#define GL_PROGRAM_LENGTH_NV 0x8627
+#define GL_PROGRAM_STRING_NV 0x8628
+#define GL_MODELVIEW_PROJECTION_NV 0x8629
+#define GL_IDENTITY_NV 0x862A
+#define GL_INVERSE_NV 0x862B
+#define GL_TRANSPOSE_NV 0x862C
+#define GL_INVERSE_TRANSPOSE_NV 0x862D
+#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E
+#define GL_MAX_TRACK_MATRICES_NV 0x862F
+#define GL_MATRIX0_NV 0x8630
+#define GL_MATRIX1_NV 0x8631
+#define GL_MATRIX2_NV 0x8632
+#define GL_MATRIX3_NV 0x8633
+#define GL_MATRIX4_NV 0x8634
+#define GL_MATRIX5_NV 0x8635
+#define GL_MATRIX6_NV 0x8636
+#define GL_MATRIX7_NV 0x8637
+#define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640
+#define GL_CURRENT_MATRIX_NV 0x8641
+#define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643
+#define GL_PROGRAM_PARAMETER_NV 0x8644
+#define GL_ATTRIB_ARRAY_POINTER_NV 0x8645
+#define GL_PROGRAM_TARGET_NV 0x8646
+#define GL_PROGRAM_RESIDENT_NV 0x8647
+#define GL_TRACK_MATRIX_NV 0x8648
+#define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649
+#define GL_VERTEX_PROGRAM_BINDING_NV 0x864A
+#define GL_PROGRAM_ERROR_POSITION_NV 0x864B
+#define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650
+#define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651
+#define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652
+#define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653
+#define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654
+#define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655
+#define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656
+#define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657
+#define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658
+#define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659
+#define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A
+#define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B
+#define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C
+#define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D
+#define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E
+#define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F
+#define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660
+#define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661
+#define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662
+#define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663
+#define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664
+#define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665
+#define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666
+#define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667
+#define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668
+#define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669
+#define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A
+#define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B
+#define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C
+#define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D
+#define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E
+#define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F
+#define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670
+#define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671
+#define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672
+#define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673
+#define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674
+#define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675
+#define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676
+#define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677
+#define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678
+#define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679
+#define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A
+#define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B
+#define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C
+#define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D
+#define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E
+#define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F
+#endif
+
+#ifndef GL_SGIX_texture_coordinate_clamp
+#define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369
+#define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A
+#define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B
+#endif
+
+#ifndef GL_SGIX_scalebias_hint
+#define GL_SCALEBIAS_HINT_SGIX 0x8322
+#endif
+
+#ifndef GL_OML_interlace
+#define GL_INTERLACE_OML 0x8980
+#define GL_INTERLACE_READ_OML 0x8981
+#endif
+
+#ifndef GL_OML_subsample
+#define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982
+#define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983
+#endif
+
+#ifndef GL_OML_resample
+#define GL_PACK_RESAMPLE_OML 0x8984
+#define GL_UNPACK_RESAMPLE_OML 0x8985
+#define GL_RESAMPLE_REPLICATE_OML 0x8986
+#define GL_RESAMPLE_ZERO_FILL_OML 0x8987
+#define GL_RESAMPLE_AVERAGE_OML 0x8988
+#define GL_RESAMPLE_DECIMATE_OML 0x8989
+#endif
+
+#ifndef GL_NV_copy_depth_to_color
+#define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E
+#define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F
+#endif
+
+#ifndef GL_ATI_envmap_bumpmap
+#define GL_BUMP_ROT_MATRIX_ATI 0x8775
+#define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776
+#define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777
+#define GL_BUMP_TEX_UNITS_ATI 0x8778
+#define GL_DUDV_ATI 0x8779
+#define GL_DU8DV8_ATI 0x877A
+#define GL_BUMP_ENVMAP_ATI 0x877B
+#define GL_BUMP_TARGET_ATI 0x877C
+#endif
+
+#ifndef GL_ATI_fragment_shader
+#define GL_FRAGMENT_SHADER_ATI 0x8920
+#define GL_REG_0_ATI 0x8921
+#define GL_REG_1_ATI 0x8922
+#define GL_REG_2_ATI 0x8923
+#define GL_REG_3_ATI 0x8924
+#define GL_REG_4_ATI 0x8925
+#define GL_REG_5_ATI 0x8926
+#define GL_REG_6_ATI 0x8927
+#define GL_REG_7_ATI 0x8928
+#define GL_REG_8_ATI 0x8929
+#define GL_REG_9_ATI 0x892A
+#define GL_REG_10_ATI 0x892B
+#define GL_REG_11_ATI 0x892C
+#define GL_REG_12_ATI 0x892D
+#define GL_REG_13_ATI 0x892E
+#define GL_REG_14_ATI 0x892F
+#define GL_REG_15_ATI 0x8930
+#define GL_REG_16_ATI 0x8931
+#define GL_REG_17_ATI 0x8932
+#define GL_REG_18_ATI 0x8933
+#define GL_REG_19_ATI 0x8934
+#define GL_REG_20_ATI 0x8935
+#define GL_REG_21_ATI 0x8936
+#define GL_REG_22_ATI 0x8937
+#define GL_REG_23_ATI 0x8938
+#define GL_REG_24_ATI 0x8939
+#define GL_REG_25_ATI 0x893A
+#define GL_REG_26_ATI 0x893B
+#define GL_REG_27_ATI 0x893C
+#define GL_REG_28_ATI 0x893D
+#define GL_REG_29_ATI 0x893E
+#define GL_REG_30_ATI 0x893F
+#define GL_REG_31_ATI 0x8940
+#define GL_CON_0_ATI 0x8941
+#define GL_CON_1_ATI 0x8942
+#define GL_CON_2_ATI 0x8943
+#define GL_CON_3_ATI 0x8944
+#define GL_CON_4_ATI 0x8945
+#define GL_CON_5_ATI 0x8946
+#define GL_CON_6_ATI 0x8947
+#define GL_CON_7_ATI 0x8948
+#define GL_CON_8_ATI 0x8949
+#define GL_CON_9_ATI 0x894A
+#define GL_CON_10_ATI 0x894B
+#define GL_CON_11_ATI 0x894C
+#define GL_CON_12_ATI 0x894D
+#define GL_CON_13_ATI 0x894E
+#define GL_CON_14_ATI 0x894F
+#define GL_CON_15_ATI 0x8950
+#define GL_CON_16_ATI 0x8951
+#define GL_CON_17_ATI 0x8952
+#define GL_CON_18_ATI 0x8953
+#define GL_CON_19_ATI 0x8954
+#define GL_CON_20_ATI 0x8955
+#define GL_CON_21_ATI 0x8956
+#define GL_CON_22_ATI 0x8957
+#define GL_CON_23_ATI 0x8958
+#define GL_CON_24_ATI 0x8959
+#define GL_CON_25_ATI 0x895A
+#define GL_CON_26_ATI 0x895B
+#define GL_CON_27_ATI 0x895C
+#define GL_CON_28_ATI 0x895D
+#define GL_CON_29_ATI 0x895E
+#define GL_CON_30_ATI 0x895F
+#define GL_CON_31_ATI 0x8960
+#define GL_MOV_ATI 0x8961
+#define GL_ADD_ATI 0x8963
+#define GL_MUL_ATI 0x8964
+#define GL_SUB_ATI 0x8965
+#define GL_DOT3_ATI 0x8966
+#define GL_DOT4_ATI 0x8967
+#define GL_MAD_ATI 0x8968
+#define GL_LERP_ATI 0x8969
+#define GL_CND_ATI 0x896A
+#define GL_CND0_ATI 0x896B
+#define GL_DOT2_ADD_ATI 0x896C
+#define GL_SECONDARY_INTERPOLATOR_ATI 0x896D
+#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E
+#define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F
+#define GL_NUM_PASSES_ATI 0x8970
+#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971
+#define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972
+#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973
+#define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974
+#define GL_COLOR_ALPHA_PAIRING_ATI 0x8975
+#define GL_SWIZZLE_STR_ATI 0x8976
+#define GL_SWIZZLE_STQ_ATI 0x8977
+#define GL_SWIZZLE_STR_DR_ATI 0x8978
+#define GL_SWIZZLE_STQ_DQ_ATI 0x8979
+#define GL_SWIZZLE_STRQ_ATI 0x897A
+#define GL_SWIZZLE_STRQ_DQ_ATI 0x897B
+#define GL_RED_BIT_ATI 0x00000001
+#define GL_GREEN_BIT_ATI 0x00000002
+#define GL_BLUE_BIT_ATI 0x00000004
+#define GL_2X_BIT_ATI 0x00000001
+#define GL_4X_BIT_ATI 0x00000002
+#define GL_8X_BIT_ATI 0x00000004
+#define GL_HALF_BIT_ATI 0x00000008
+#define GL_QUARTER_BIT_ATI 0x00000010
+#define GL_EIGHTH_BIT_ATI 0x00000020
+#define GL_SATURATE_BIT_ATI 0x00000040
+#define GL_COMP_BIT_ATI 0x00000002
+#define GL_NEGATE_BIT_ATI 0x00000004
+#define GL_BIAS_BIT_ATI 0x00000008
+#endif
+
+#ifndef GL_ATI_pn_triangles
+#define GL_PN_TRIANGLES_ATI 0x87F0
+#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1
+#define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2
+#define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3
+#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4
+#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5
+#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6
+#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7
+#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8
+#endif
+
+#ifndef GL_ATI_vertex_array_object
+#define GL_STATIC_ATI 0x8760
+#define GL_DYNAMIC_ATI 0x8761
+#define GL_PRESERVE_ATI 0x8762
+#define GL_DISCARD_ATI 0x8763
+#define GL_OBJECT_BUFFER_SIZE_ATI 0x8764
+#define GL_OBJECT_BUFFER_USAGE_ATI 0x8765
+#define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766
+#define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767
+#endif
+
+#ifndef GL_EXT_vertex_shader
+#define GL_VERTEX_SHADER_EXT 0x8780
+#define GL_VERTEX_SHADER_BINDING_EXT 0x8781
+#define GL_OP_INDEX_EXT 0x8782
+#define GL_OP_NEGATE_EXT 0x8783
+#define GL_OP_DOT3_EXT 0x8784
+#define GL_OP_DOT4_EXT 0x8785
+#define GL_OP_MUL_EXT 0x8786
+#define GL_OP_ADD_EXT 0x8787
+#define GL_OP_MADD_EXT 0x8788
+#define GL_OP_FRAC_EXT 0x8789
+#define GL_OP_MAX_EXT 0x878A
+#define GL_OP_MIN_EXT 0x878B
+#define GL_OP_SET_GE_EXT 0x878C
+#define GL_OP_SET_LT_EXT 0x878D
+#define GL_OP_CLAMP_EXT 0x878E
+#define GL_OP_FLOOR_EXT 0x878F
+#define GL_OP_ROUND_EXT 0x8790
+#define GL_OP_EXP_BASE_2_EXT 0x8791
+#define GL_OP_LOG_BASE_2_EXT 0x8792
+#define GL_OP_POWER_EXT 0x8793
+#define GL_OP_RECIP_EXT 0x8794
+#define GL_OP_RECIP_SQRT_EXT 0x8795
+#define GL_OP_SUB_EXT 0x8796
+#define GL_OP_CROSS_PRODUCT_EXT 0x8797
+#define GL_OP_MULTIPLY_MATRIX_EXT 0x8798
+#define GL_OP_MOV_EXT 0x8799
+#define GL_OUTPUT_VERTEX_EXT 0x879A
+#define GL_OUTPUT_COLOR0_EXT 0x879B
+#define GL_OUTPUT_COLOR1_EXT 0x879C
+#define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D
+#define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E
+#define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F
+#define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0
+#define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1
+#define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2
+#define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3
+#define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4
+#define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5
+#define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6
+#define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7
+#define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8
+#define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9
+#define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA
+#define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB
+#define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC
+#define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD
+#define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE
+#define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF
+#define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0
+#define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1
+#define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2
+#define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3
+#define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4
+#define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5
+#define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6
+#define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7
+#define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8
+#define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9
+#define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA
+#define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB
+#define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC
+#define GL_OUTPUT_FOG_EXT 0x87BD
+#define GL_SCALAR_EXT 0x87BE
+#define GL_VECTOR_EXT 0x87BF
+#define GL_MATRIX_EXT 0x87C0
+#define GL_VARIANT_EXT 0x87C1
+#define GL_INVARIANT_EXT 0x87C2
+#define GL_LOCAL_CONSTANT_EXT 0x87C3
+#define GL_LOCAL_EXT 0x87C4
+#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5
+#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6
+#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7
+#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8
+#define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE
+#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF
+#define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0
+#define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1
+#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2
+#define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3
+#define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4
+#define GL_X_EXT 0x87D5
+#define GL_Y_EXT 0x87D6
+#define GL_Z_EXT 0x87D7
+#define GL_W_EXT 0x87D8
+#define GL_NEGATIVE_X_EXT 0x87D9
+#define GL_NEGATIVE_Y_EXT 0x87DA
+#define GL_NEGATIVE_Z_EXT 0x87DB
+#define GL_NEGATIVE_W_EXT 0x87DC
+#define GL_ZERO_EXT 0x87DD
+#define GL_ONE_EXT 0x87DE
+#define GL_NEGATIVE_ONE_EXT 0x87DF
+#define GL_NORMALIZED_RANGE_EXT 0x87E0
+#define GL_FULL_RANGE_EXT 0x87E1
+#define GL_CURRENT_VERTEX_EXT 0x87E2
+#define GL_MVP_MATRIX_EXT 0x87E3
+#define GL_VARIANT_VALUE_EXT 0x87E4
+#define GL_VARIANT_DATATYPE_EXT 0x87E5
+#define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6
+#define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7
+#define GL_VARIANT_ARRAY_EXT 0x87E8
+#define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9
+#define GL_INVARIANT_VALUE_EXT 0x87EA
+#define GL_INVARIANT_DATATYPE_EXT 0x87EB
+#define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC
+#define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED
+#endif
+
+#ifndef GL_ATI_vertex_streams
+#define GL_MAX_VERTEX_STREAMS_ATI 0x876B
+#define GL_VERTEX_STREAM0_ATI 0x876C
+#define GL_VERTEX_STREAM1_ATI 0x876D
+#define GL_VERTEX_STREAM2_ATI 0x876E
+#define GL_VERTEX_STREAM3_ATI 0x876F
+#define GL_VERTEX_STREAM4_ATI 0x8770
+#define GL_VERTEX_STREAM5_ATI 0x8771
+#define GL_VERTEX_STREAM6_ATI 0x8772
+#define GL_VERTEX_STREAM7_ATI 0x8773
+#define GL_VERTEX_SOURCE_ATI 0x8774
+#endif
+
+#ifndef GL_ATI_element_array
+#define GL_ELEMENT_ARRAY_ATI 0x8768
+#define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769
+#define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A
+#endif
+
+#ifndef GL_SUN_mesh_array
+#define GL_QUAD_MESH_SUN 0x8614
+#define GL_TRIANGLE_MESH_SUN 0x8615
+#endif
+
+#ifndef GL_SUN_slice_accum
+#define GL_SLICE_ACCUM_SUN 0x85CC
+#endif
+
+#ifndef GL_NV_multisample_filter_hint
+#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534
+#endif
+
+#ifndef GL_NV_depth_clamp
+#define GL_DEPTH_CLAMP_NV 0x864F
+#endif
+
+#ifndef GL_NV_occlusion_query
+#define GL_PIXEL_COUNTER_BITS_NV 0x8864
+#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865
+#define GL_PIXEL_COUNT_NV 0x8866
+#define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867
+#endif
+
+#ifndef GL_NV_point_sprite
+#define GL_POINT_SPRITE_NV 0x8861
+#define GL_COORD_REPLACE_NV 0x8862
+#define GL_POINT_SPRITE_R_MODE_NV 0x8863
+#endif
+
+#ifndef GL_NV_texture_shader3
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853
+#define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854
+#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857
+#define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858
+#define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859
+#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A
+#define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B
+#define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C
+#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D
+#define GL_HILO8_NV 0x885E
+#define GL_SIGNED_HILO8_NV 0x885F
+#define GL_FORCE_BLUE_TO_ONE_NV 0x8860
+#endif
+
+#ifndef GL_NV_vertex_program1_1
+#endif
+
+#ifndef GL_EXT_shadow_funcs
+#endif
+
+#ifndef GL_EXT_stencil_two_side
+#define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910
+#define GL_ACTIVE_STENCIL_FACE_EXT 0x8911
+#endif
+
+#ifndef GL_ATI_text_fragment_shader
+#define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200
+#endif
+
+#ifndef GL_APPLE_client_storage
+#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2
+#endif
+
+#ifndef GL_APPLE_element_array
+#define GL_ELEMENT_ARRAY_APPLE 0x8768
+#define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8769
+#define GL_ELEMENT_ARRAY_POINTER_APPLE 0x876A
+#endif
+
+#ifndef GL_APPLE_fence
+#define GL_DRAW_PIXELS_APPLE 0x8A0A
+#define GL_FENCE_APPLE 0x8A0B
+#endif
+
+#ifndef GL_APPLE_vertex_array_object
+#define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5
+#endif
+
+#ifndef GL_APPLE_vertex_array_range
+#define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E
+#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F
+#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521
+#define GL_STORAGE_CACHED_APPLE 0x85BE
+#define GL_STORAGE_SHARED_APPLE 0x85BF
+#endif
+
+#ifndef GL_APPLE_ycbcr_422
+#define GL_YCBCR_422_APPLE 0x85B9
+#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
+#endif
+
+#ifndef GL_S3_s3tc
+#define GL_RGB_S3TC 0x83A0
+#define GL_RGB4_S3TC 0x83A1
+#define GL_RGBA_S3TC 0x83A2
+#define GL_RGBA4_S3TC 0x83A3
+#endif
+
+#ifndef GL_ATI_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_ATI 0x8824
+#define GL_DRAW_BUFFER0_ATI 0x8825
+#define GL_DRAW_BUFFER1_ATI 0x8826
+#define GL_DRAW_BUFFER2_ATI 0x8827
+#define GL_DRAW_BUFFER3_ATI 0x8828
+#define GL_DRAW_BUFFER4_ATI 0x8829
+#define GL_DRAW_BUFFER5_ATI 0x882A
+#define GL_DRAW_BUFFER6_ATI 0x882B
+#define GL_DRAW_BUFFER7_ATI 0x882C
+#define GL_DRAW_BUFFER8_ATI 0x882D
+#define GL_DRAW_BUFFER9_ATI 0x882E
+#define GL_DRAW_BUFFER10_ATI 0x882F
+#define GL_DRAW_BUFFER11_ATI 0x8830
+#define GL_DRAW_BUFFER12_ATI 0x8831
+#define GL_DRAW_BUFFER13_ATI 0x8832
+#define GL_DRAW_BUFFER14_ATI 0x8833
+#define GL_DRAW_BUFFER15_ATI 0x8834
+#endif
+
+#ifndef GL_ATI_pixel_format_float
+#define GL_TYPE_RGBA_FLOAT_ATI 0x8820
+#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835
+#endif
+
+#ifndef GL_ATI_texture_env_combine3
+#define GL_MODULATE_ADD_ATI 0x8744
+#define GL_MODULATE_SIGNED_ADD_ATI 0x8745
+#define GL_MODULATE_SUBTRACT_ATI 0x8746
+#endif
+
+#ifndef GL_ATI_texture_float
+#define GL_RGBA_FLOAT32_ATI 0x8814
+#define GL_RGB_FLOAT32_ATI 0x8815
+#define GL_ALPHA_FLOAT32_ATI 0x8816
+#define GL_INTENSITY_FLOAT32_ATI 0x8817
+#define GL_LUMINANCE_FLOAT32_ATI 0x8818
+#define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819
+#define GL_RGBA_FLOAT16_ATI 0x881A
+#define GL_RGB_FLOAT16_ATI 0x881B
+#define GL_ALPHA_FLOAT16_ATI 0x881C
+#define GL_INTENSITY_FLOAT16_ATI 0x881D
+#define GL_LUMINANCE_FLOAT16_ATI 0x881E
+#define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F
+#endif
+
+#ifndef GL_NV_float_buffer
+#define GL_FLOAT_R_NV 0x8880
+#define GL_FLOAT_RG_NV 0x8881
+#define GL_FLOAT_RGB_NV 0x8882
+#define GL_FLOAT_RGBA_NV 0x8883
+#define GL_FLOAT_R16_NV 0x8884
+#define GL_FLOAT_R32_NV 0x8885
+#define GL_FLOAT_RG16_NV 0x8886
+#define GL_FLOAT_RG32_NV 0x8887
+#define GL_FLOAT_RGB16_NV 0x8888
+#define GL_FLOAT_RGB32_NV 0x8889
+#define GL_FLOAT_RGBA16_NV 0x888A
+#define GL_FLOAT_RGBA32_NV 0x888B
+#define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C
+#define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D
+#define GL_FLOAT_RGBA_MODE_NV 0x888E
+#endif
+
+#ifndef GL_NV_fragment_program
+#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868
+#define GL_FRAGMENT_PROGRAM_NV 0x8870
+#define GL_MAX_TEXTURE_COORDS_NV 0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872
+#define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873
+#define GL_PROGRAM_ERROR_STRING_NV 0x8874
+#endif
+
+#ifndef GL_NV_half_float
+#define GL_HALF_FLOAT_NV 0x140B
+#endif
+
+#ifndef GL_NV_pixel_data_range
+#define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878
+#define GL_READ_PIXEL_DATA_RANGE_NV 0x8879
+#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A
+#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B
+#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C
+#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D
+#endif
+
+#ifndef GL_NV_primitive_restart
+#define GL_PRIMITIVE_RESTART_NV 0x8558
+#define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559
+#endif
+
+#ifndef GL_NV_texture_expand_normal
+#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F
+#endif
+
+#ifndef GL_NV_vertex_program2
+#endif
+
+#ifndef GL_ATI_map_object_buffer
+#endif
+
+#ifndef GL_ATI_separate_stencil
+#define GL_STENCIL_BACK_FUNC_ATI 0x8800
+#define GL_STENCIL_BACK_FAIL_ATI 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803
+#endif
+
+#ifndef GL_ATI_vertex_attrib_array_object
+#endif
+
+#ifndef GL_OES_read_format
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
+#endif
+
+#ifndef GL_EXT_depth_bounds_test
+#define GL_DEPTH_BOUNDS_TEST_EXT 0x8890
+#define GL_DEPTH_BOUNDS_EXT 0x8891
+#endif
+
+#ifndef GL_EXT_texture_mirror_clamp
+#define GL_MIRROR_CLAMP_EXT 0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743
+#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912
+#endif
+
+#ifndef GL_EXT_blend_equation_separate
+#define GL_BLEND_EQUATION_RGB_EXT GL_BLEND_EQUATION
+#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D
+#endif
+
+#ifndef GL_MESA_pack_invert
+#define GL_PACK_INVERT_MESA 0x8758
+#endif
+
+#ifndef GL_MESA_ycbcr_texture
+#define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB
+#define GL_YCBCR_MESA 0x8757
+#endif
+
+#ifndef GL_EXT_pixel_buffer_object
+#define GL_PIXEL_PACK_BUFFER_EXT 0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF
+#endif
+
+#ifndef GL_NV_fragment_program_option
+#endif
+
+#ifndef GL_NV_fragment_program2
+#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4
+#define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5
+#define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6
+#define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7
+#define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8
+#endif
+
+#ifndef GL_NV_vertex_program2_option
+/* reuse GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV */
+/* reuse GL_MAX_PROGRAM_CALL_DEPTH_NV */
+#endif
+
+#ifndef GL_NV_vertex_program3
+/* reuse GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */
+#endif
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
+#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8
+#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6
+#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
+#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD
+#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
+#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
+#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
+#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
+#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
+#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
+#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
+#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
+#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
+#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
+#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
+#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
+#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
+#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
+#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
+#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
+#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
+#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
+#define GL_STENCIL_ATTACHMENT_EXT 0x8D20
+#define GL_FRAMEBUFFER_EXT 0x8D40
+#define GL_RENDERBUFFER_EXT 0x8D41
+#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42
+#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
+#define GL_STENCIL_INDEX1_EXT 0x8D46
+#define GL_STENCIL_INDEX4_EXT 0x8D47
+#define GL_STENCIL_INDEX8_EXT 0x8D48
+#define GL_STENCIL_INDEX16_EXT 0x8D49
+#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
+#endif
+
+#ifndef GL_GREMEDY_string_marker
+#endif
+
+
+/*************************************************************/
+
+#include <stddef.h>
+#ifndef GL_VERSION_2_0
+/* GL type for program/shader text */
+typedef char GLchar; /* native character */
+#endif
+
+#ifndef GL_VERSION_1_5
+/* GL types for handling large vertex buffer objects */
+typedef ptrdiff_t GLintptr;
+typedef ptrdiff_t GLsizeiptr;
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+/* GL types for handling large vertex buffer objects */
+typedef ptrdiff_t GLintptrARB;
+typedef ptrdiff_t GLsizeiptrARB;
+#endif
+
+#ifndef GL_ARB_shader_objects
+/* GL types for handling shader object handles and program/shader text */
+typedef char GLcharARB; /* native character */
+typedef unsigned int GLhandleARB; /* shader object handle */
+#endif
+
+/* GL types for "half" precision (s10e5) float data in host memory */
+#ifndef GL_ARB_half_float_pixel
+typedef unsigned short GLhalfARB;
+#endif
+
+#ifndef GL_NV_half_float
+typedef unsigned short GLhalfNV;
+#endif
+
+#ifndef GL_VERSION_1_2
+#define GL_VERSION_1_2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendColor (GLclampf, GLclampf, GLclampf, GLclampf);
+GLAPI void APIENTRY glBlendEquation (GLenum);
+GLAPI void APIENTRY glDrawRangeElements (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTable (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTableParameterfv (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glColorTableParameteriv (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyColorTable (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glGetColorTable (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetColorTableParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glColorSubTable (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyColorSubTable (GLenum, GLsizei, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glConvolutionFilter1D (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionParameterf (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glConvolutionParameterfv (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glConvolutionParameteri (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glConvolutionParameteriv (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetConvolutionFilter (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetSeparableFilter (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *);
+GLAPI void APIENTRY glSeparableFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *);
+GLAPI void APIENTRY glGetHistogram (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetHistogramParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetHistogramParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMinmax (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glHistogram (GLenum, GLsizei, GLenum, GLboolean);
+GLAPI void APIENTRY glMinmax (GLenum, GLenum, GLboolean);
+GLAPI void APIENTRY glResetHistogram (GLenum);
+GLAPI void APIENTRY glResetMinmax (GLenum);
+GLAPI void APIENTRY glTexImage3D (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_VERSION_1_3
+#define GL_VERSION_1_3 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTexture (GLenum);
+GLAPI void APIENTRY glClientActiveTexture (GLenum);
+GLAPI void APIENTRY glMultiTexCoord1d (GLenum, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord1dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord1f (GLenum, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord1fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord1i (GLenum, GLint);
+GLAPI void APIENTRY glMultiTexCoord1iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord1s (GLenum, GLshort);
+GLAPI void APIENTRY glMultiTexCoord1sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord2d (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord2dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord2f (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord2fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord2i (GLenum, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord2iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord2s (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord2sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord3d (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord3dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord3f (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord3fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord3i (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord3iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord3s (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord3sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord4d (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord4dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord4f (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord4fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord4i (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord4iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord4s (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord4sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *);
+GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *);
+GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *);
+GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *);
+GLAPI void APIENTRY glSampleCoverage (GLclampf, GLboolean);
+GLAPI void APIENTRY glCompressedTexImage3D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage1D (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glGetCompressedTexImage (GLenum, GLint, GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img);
+#endif
+
+#ifndef GL_VERSION_1_4
+#define GL_VERSION_1_4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparate (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glFogCoordf (GLfloat);
+GLAPI void APIENTRY glFogCoordfv (const GLfloat *);
+GLAPI void APIENTRY glFogCoordd (GLdouble);
+GLAPI void APIENTRY glFogCoorddv (const GLdouble *);
+GLAPI void APIENTRY glFogCoordPointer (GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glMultiDrawArrays (GLenum, GLint *, GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawElements (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+GLAPI void APIENTRY glPointParameterf (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glPointParameteri (GLenum, GLint);
+GLAPI void APIENTRY glPointParameteriv (GLenum, const GLint *);
+GLAPI void APIENTRY glSecondaryColor3b (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *);
+GLAPI void APIENTRY glSecondaryColor3d (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *);
+GLAPI void APIENTRY glSecondaryColor3f (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *);
+GLAPI void APIENTRY glSecondaryColor3i (GLint, GLint, GLint);
+GLAPI void APIENTRY glSecondaryColor3iv (const GLint *);
+GLAPI void APIENTRY glSecondaryColor3s (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *);
+GLAPI void APIENTRY glSecondaryColor3ub (GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *);
+GLAPI void APIENTRY glSecondaryColor3ui (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *);
+GLAPI void APIENTRY glSecondaryColor3us (GLushort, GLushort, GLushort);
+GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *);
+GLAPI void APIENTRY glSecondaryColorPointer (GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glWindowPos2d (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dv (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2f (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fv (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2i (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2iv (const GLint *);
+GLAPI void APIENTRY glWindowPos2s (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2sv (const GLshort *);
+GLAPI void APIENTRY glWindowPos3d (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dv (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3f (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fv (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3i (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3iv (const GLint *);
+GLAPI void APIENTRY glWindowPos3s (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3sv (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_VERSION_1_5
+#define GL_VERSION_1_5 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueries (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteQueries (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsQuery (GLuint);
+GLAPI void APIENTRY glBeginQuery (GLenum, GLuint);
+GLAPI void APIENTRY glEndQuery (GLenum);
+GLAPI void APIENTRY glGetQueryiv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectuiv (GLuint, GLenum, GLuint *);
+GLAPI void APIENTRY glBindBuffer (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteBuffers (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenBuffers (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsBuffer (GLuint);
+GLAPI void APIENTRY glBufferData (GLenum, GLsizeiptr, const GLvoid *, GLenum);
+GLAPI void APIENTRY glBufferSubData (GLenum, GLintptr, GLsizeiptr, const GLvoid *);
+GLAPI void APIENTRY glGetBufferSubData (GLenum, GLintptr, GLsizeiptr, GLvoid *);
+GLAPI GLvoid* APIENTRY glMapBuffer (GLenum, GLenum);
+GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum);
+GLAPI void APIENTRY glGetBufferParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetBufferPointerv (GLenum, GLenum, GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data);
+typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params);
+#endif
+
+#ifndef GL_VERSION_2_0
+#define GL_VERSION_2_0 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparate (GLenum, GLenum);
+GLAPI void APIENTRY glDrawBuffers (GLsizei, const GLenum *);
+GLAPI void APIENTRY glStencilOpSeparate (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glStencilFuncSeparate (GLenum, GLenum, GLint, GLuint);
+GLAPI void APIENTRY glStencilMaskSeparate (GLenum, GLuint);
+GLAPI void APIENTRY glAttachShader (GLuint, GLuint);
+GLAPI void APIENTRY glBindAttribLocation (GLuint, GLuint, const GLchar *);
+GLAPI void APIENTRY glCompileShader (GLuint);
+GLAPI GLuint APIENTRY glCreateProgram (void);
+GLAPI GLuint APIENTRY glCreateShader (GLenum);
+GLAPI void APIENTRY glDeleteProgram (GLuint);
+GLAPI void APIENTRY glDeleteShader (GLuint);
+GLAPI void APIENTRY glDetachShader (GLuint, GLuint);
+GLAPI void APIENTRY glDisableVertexAttribArray (GLuint);
+GLAPI void APIENTRY glEnableVertexAttribArray (GLuint);
+GLAPI void APIENTRY glGetActiveAttrib (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);
+GLAPI void APIENTRY glGetActiveUniform (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);
+GLAPI void APIENTRY glGetAttachedShaders (GLuint, GLsizei, GLsizei *, GLuint *);
+GLAPI GLint APIENTRY glGetAttribLocation (GLuint, const GLchar *);
+GLAPI void APIENTRY glGetProgramiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramInfoLog (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI void APIENTRY glGetShaderiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetShaderInfoLog (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI void APIENTRY glGetShaderSource (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI GLint APIENTRY glGetUniformLocation (GLuint, const GLchar *);
+GLAPI void APIENTRY glGetUniformfv (GLuint, GLint, GLfloat *);
+GLAPI void APIENTRY glGetUniformiv (GLuint, GLint, GLint *);
+GLAPI void APIENTRY glGetVertexAttribdv (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfv (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgram (GLuint);
+GLAPI GLboolean APIENTRY glIsShader (GLuint);
+GLAPI void APIENTRY glLinkProgram (GLuint);
+GLAPI void APIENTRY glShaderSource (GLuint, GLsizei, const GLchar* *, const GLint *);
+GLAPI void APIENTRY glUseProgram (GLuint);
+GLAPI void APIENTRY glUniform1f (GLint, GLfloat);
+GLAPI void APIENTRY glUniform2f (GLint, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform3f (GLint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform4f (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform1i (GLint, GLint);
+GLAPI void APIENTRY glUniform2i (GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform3i (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform4i (GLint, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform1fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform2fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform3fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform4fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform1iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform2iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform3iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform4iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniformMatrix2fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix3fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix4fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glValidateProgram (GLuint);
+GLAPI void APIENTRY glVertexAttrib1d (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1f (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1s (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2d (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2f (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2s (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3d (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3f (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3s (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4Niv (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4Nub (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttrib4bv (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4d (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4f (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4iv (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4s (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubv (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4uiv (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4usv (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttribPointer (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);
+typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);
+typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
+typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);
+typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length);
+typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_ARB_multitexture
+#define GL_ARB_multitexture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTextureARB (GLenum);
+GLAPI void APIENTRY glClientActiveTextureARB (GLenum);
+GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum, GLint);
+GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum, GLshort);
+GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum, const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+#endif
+
+#ifndef GL_ARB_transpose_matrix
+#define GL_ARB_transpose_matrix 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *);
+GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *);
+GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *);
+GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+#endif
+
+#ifndef GL_ARB_multisample
+#define GL_ARB_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleCoverageARB (GLclampf, GLboolean);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert);
+#endif
+
+#ifndef GL_ARB_texture_env_add
+#define GL_ARB_texture_env_add 1
+#endif
+
+#ifndef GL_ARB_texture_cube_map
+#define GL_ARB_texture_cube_map 1
+#endif
+
+#ifndef GL_ARB_texture_compression
+#define GL_ARB_texture_compression 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum, GLint, GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img);
+#endif
+
+#ifndef GL_ARB_texture_border_clamp
+#define GL_ARB_texture_border_clamp 1
+#endif
+
+#ifndef GL_ARB_point_parameters
+#define GL_ARB_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfARB (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvARB (GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_ARB_vertex_blend
+#define GL_ARB_vertex_blend 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWeightbvARB (GLint, const GLbyte *);
+GLAPI void APIENTRY glWeightsvARB (GLint, const GLshort *);
+GLAPI void APIENTRY glWeightivARB (GLint, const GLint *);
+GLAPI void APIENTRY glWeightfvARB (GLint, const GLfloat *);
+GLAPI void APIENTRY glWeightdvARB (GLint, const GLdouble *);
+GLAPI void APIENTRY glWeightubvARB (GLint, const GLubyte *);
+GLAPI void APIENTRY glWeightusvARB (GLint, const GLushort *);
+GLAPI void APIENTRY glWeightuivARB (GLint, const GLuint *);
+GLAPI void APIENTRY glWeightPointerARB (GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexBlendARB (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
+typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count);
+#endif
+
+#ifndef GL_ARB_matrix_palette
+#define GL_ARB_matrix_palette 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint);
+GLAPI void APIENTRY glMatrixIndexubvARB (GLint, const GLubyte *);
+GLAPI void APIENTRY glMatrixIndexusvARB (GLint, const GLushort *);
+GLAPI void APIENTRY glMatrixIndexuivARB (GLint, const GLuint *);
+GLAPI void APIENTRY glMatrixIndexPointerARB (GLint, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_ARB_texture_env_combine
+#define GL_ARB_texture_env_combine 1
+#endif
+
+#ifndef GL_ARB_texture_env_crossbar
+#define GL_ARB_texture_env_crossbar 1
+#endif
+
+#ifndef GL_ARB_texture_env_dot3
+#define GL_ARB_texture_env_dot3 1
+#endif
+
+#ifndef GL_ARB_texture_mirrored_repeat
+#define GL_ARB_texture_mirrored_repeat 1
+#endif
+
+#ifndef GL_ARB_depth_texture
+#define GL_ARB_depth_texture 1
+#endif
+
+#ifndef GL_ARB_shadow
+#define GL_ARB_shadow 1
+#endif
+
+#ifndef GL_ARB_shadow_ambient
+#define GL_ARB_shadow_ambient 1
+#endif
+
+#ifndef GL_ARB_window_pos
+#define GL_ARB_window_pos 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dARB (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2fARB (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2iARB (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2ivARB (const GLint *);
+GLAPI void APIENTRY glWindowPos2sARB (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2svARB (const GLshort *);
+GLAPI void APIENTRY glWindowPos3dARB (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3fARB (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3iARB (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3ivARB (const GLint *);
+GLAPI void APIENTRY glWindowPos3sARB (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3svARB (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_ARB_vertex_program
+#define GL_ARB_vertex_program 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttrib1dARB (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1fARB (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1sARB (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2dARB (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2fARB (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2sARB (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3dARB (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3fARB (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3sARB (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4dARB (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4fARB (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4sARB (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttribPointerARB (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint);
+GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint);
+GLAPI void APIENTRY glProgramStringARB (GLenum, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glBindProgramARB (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteProgramsARB (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenProgramsARB (GLsizei, GLuint *);
+GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum, GLuint, GLdouble *);
+GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum, GLuint, GLfloat *);
+GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum, GLuint, GLdouble *);
+GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum, GLuint, GLfloat *);
+GLAPI void APIENTRY glGetProgramivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramStringARB (GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribivARB (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgramARB (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string);
+typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program);
+#endif
+
+#ifndef GL_ARB_fragment_program
+#define GL_ARB_fragment_program 1
+/* All ARB_fragment_program entry points are shared with ARB_vertex_program. */
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_ARB_vertex_buffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindBufferARB (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteBuffersARB (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenBuffersARB (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsBufferARB (GLuint);
+GLAPI void APIENTRY glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum);
+GLAPI void APIENTRY glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *);
+GLAPI void APIENTRY glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *);
+GLAPI GLvoid* APIENTRY glMapBufferARB (GLenum, GLenum);
+GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum);
+GLAPI void APIENTRY glGetBufferParameterivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data);
+typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params);
+#endif
+
+#ifndef GL_ARB_occlusion_query
+#define GL_ARB_occlusion_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueriesARB (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteQueriesARB (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsQueryARB (GLuint);
+GLAPI void APIENTRY glBeginQueryARB (GLenum, GLuint);
+GLAPI void APIENTRY glEndQueryARB (GLenum);
+GLAPI void APIENTRY glGetQueryivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectivARB (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint, GLenum, GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
+#ifndef GL_ARB_shader_objects
+#define GL_ARB_shader_objects 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB);
+GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum);
+GLAPI void APIENTRY glDetachObjectARB (GLhandleARB, GLhandleARB);
+GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum);
+GLAPI void APIENTRY glShaderSourceARB (GLhandleARB, GLsizei, const GLcharARB* *, const GLint *);
+GLAPI void APIENTRY glCompileShaderARB (GLhandleARB);
+GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void);
+GLAPI void APIENTRY glAttachObjectARB (GLhandleARB, GLhandleARB);
+GLAPI void APIENTRY glLinkProgramARB (GLhandleARB);
+GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB);
+GLAPI void APIENTRY glValidateProgramARB (GLhandleARB);
+GLAPI void APIENTRY glUniform1fARB (GLint, GLfloat);
+GLAPI void APIENTRY glUniform2fARB (GLint, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform3fARB (GLint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform4fARB (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform1iARB (GLint, GLint);
+GLAPI void APIENTRY glUniform2iARB (GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform3iARB (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform4iARB (GLint, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform1fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform2fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform3fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform4fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform1ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform2ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform3ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform4ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniformMatrix2fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix3fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix4fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB, GLenum, GLint *);
+GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *);
+GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB, const GLcharARB *);
+GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);
+GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB, GLint, GLfloat *);
+GLAPI void APIENTRY glGetUniformivARB (GLhandleARB, GLint, GLint *);
+GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj);
+typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);
+typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length);
+typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void);
+typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);
+typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
+typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);
+#endif
+
+#ifndef GL_ARB_vertex_shader
+#define GL_ARB_vertex_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB, GLuint, const GLcharARB *);
+GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);
+GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB, const GLcharARB *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+#endif
+
+#ifndef GL_ARB_fragment_shader
+#define GL_ARB_fragment_shader 1
+#endif
+
+#ifndef GL_ARB_shading_language_100
+#define GL_ARB_shading_language_100 1
+#endif
+
+#ifndef GL_ARB_texture_non_power_of_two
+#define GL_ARB_texture_non_power_of_two 1
+#endif
+
+#ifndef GL_ARB_point_sprite
+#define GL_ARB_point_sprite 1
+#endif
+
+#ifndef GL_ARB_fragment_program_shadow
+#define GL_ARB_fragment_program_shadow 1
+#endif
+
+#ifndef GL_ARB_draw_buffers
+#define GL_ARB_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersARB (GLsizei, const GLenum *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+#ifndef GL_ARB_texture_rectangle
+#define GL_ARB_texture_rectangle 1
+#endif
+
+#ifndef GL_ARB_color_buffer_float
+#define GL_ARB_color_buffer_float 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glClampColorARB (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);
+#endif
+
+#ifndef GL_ARB_half_float_pixel
+#define GL_ARB_half_float_pixel 1
+#endif
+
+#ifndef GL_ARB_texture_float
+#define GL_ARB_texture_float 1
+#endif
+
+#ifndef GL_ARB_pixel_buffer_object
+#define GL_ARB_pixel_buffer_object 1
+#endif
+
+#ifndef GL_EXT_abgr
+#define GL_EXT_abgr 1
+#endif
+
+#ifndef GL_EXT_blend_color
+#define GL_EXT_blend_color 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendColorEXT (GLclampf, GLclampf, GLclampf, GLclampf);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+#endif
+
+#ifndef GL_EXT_polygon_offset
+#define GL_EXT_polygon_offset 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias);
+#endif
+
+#ifndef GL_EXT_texture
+#define GL_EXT_texture 1
+#endif
+
+#ifndef GL_EXT_texture3D
+#define GL_EXT_texture3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage3DEXT (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_SGIS_texture_filter4
+#define GL_SGIS_texture_filter4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum, GLenum, GLsizei, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights);
+typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);
+#endif
+
+#ifndef GL_EXT_subtexture
+#define GL_EXT_subtexture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexSubImage1DEXT (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_EXT_copy_texture
+#define GL_EXT_copy_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint);
+GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint);
+GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_EXT_histogram
+#define GL_EXT_histogram 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetHistogramEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMinmaxEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glHistogramEXT (GLenum, GLsizei, GLenum, GLboolean);
+GLAPI void APIENTRY glMinmaxEXT (GLenum, GLenum, GLboolean);
+GLAPI void APIENTRY glResetHistogramEXT (GLenum);
+GLAPI void APIENTRY glResetMinmaxEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target);
+#endif
+
+#ifndef GL_EXT_convolution
+#define GL_EXT_convolution 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *);
+GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+#endif
+
+#ifndef GL_EXT_color_matrix
+#define GL_EXT_color_matrix 1
+#endif
+
+#ifndef GL_SGI_color_table
+#define GL_SGI_color_table 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableSGI (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glColorTableParameterivSGI (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyColorTableSGI (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glGetColorTableSGI (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_SGIX_pixel_texture
+#define GL_SGIX_pixel_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenSGIX (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode);
+#endif
+
+#ifndef GL_SGIS_pixel_texture
+#define GL_SGIS_pixel_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum, GLint);
+GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum, const GLint *);
+GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum, GLfloat);
+GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum, GLint *);
+GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_SGIS_texture4D
+#define GL_SGIS_texture4D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage4DSGIS (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_SGI_texture_color_table
+#define GL_SGI_texture_color_table 1
+#endif
+
+#ifndef GL_EXT_cmyka
+#define GL_EXT_cmyka 1
+#endif
+
+#ifndef GL_EXT_texture_object
+#define GL_EXT_texture_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei, const GLuint *, GLboolean *);
+GLAPI void APIENTRY glBindTextureEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenTexturesEXT (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint);
+GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei, const GLuint *, const GLclampf *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture);
+typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures);
+typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures);
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture);
+typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities);
+#endif
+
+#ifndef GL_SGIS_detail_texture
+#define GL_SGIS_detail_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#endif
+
+#ifndef GL_SGIS_sharpen_texture
+#define GL_SGIS_sharpen_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#endif
+
+#ifndef GL_EXT_packed_pixels
+#define GL_EXT_packed_pixels 1
+#endif
+
+#ifndef GL_SGIS_texture_lod
+#define GL_SGIS_texture_lod 1
+#endif
+
+#ifndef GL_SGIS_multisample
+#define GL_SGIS_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskSGIS (GLclampf, GLboolean);
+GLAPI void APIENTRY glSamplePatternSGIS (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern);
+#endif
+
+#ifndef GL_EXT_rescale_normal
+#define GL_EXT_rescale_normal 1
+#endif
+
+#ifndef GL_EXT_vertex_array
+#define GL_EXT_vertex_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glArrayElementEXT (GLint);
+GLAPI void APIENTRY glColorPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glDrawArraysEXT (GLenum, GLint, GLsizei);
+GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei, GLsizei, const GLboolean *);
+GLAPI void APIENTRY glGetPointervEXT (GLenum, GLvoid* *);
+GLAPI void APIENTRY glIndexPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glNormalPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glTexCoordPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i);
+typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer);
+typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params);
+typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_misc_attribute
+#define GL_EXT_misc_attribute 1
+#endif
+
+#ifndef GL_SGIS_generate_mipmap
+#define GL_SGIS_generate_mipmap 1
+#endif
+
+#ifndef GL_SGIX_clipmap
+#define GL_SGIX_clipmap 1
+#endif
+
+#ifndef GL_SGIX_shadow
+#define GL_SGIX_shadow 1
+#endif
+
+#ifndef GL_SGIS_texture_edge_clamp
+#define GL_SGIS_texture_edge_clamp 1
+#endif
+
+#ifndef GL_SGIS_texture_border_clamp
+#define GL_SGIS_texture_border_clamp 1
+#endif
+
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode);
+#endif
+
+#ifndef GL_EXT_blend_subtract
+#define GL_EXT_blend_subtract 1
+#endif
+
+#ifndef GL_EXT_blend_logic_op
+#define GL_EXT_blend_logic_op 1
+#endif
+
+#ifndef GL_SGIX_interlace
+#define GL_SGIX_interlace 1
+#endif
+
+#ifndef GL_SGIX_pixel_tiles
+#define GL_SGIX_pixel_tiles 1
+#endif
+
+#ifndef GL_SGIX_texture_select
+#define GL_SGIX_texture_select 1
+#endif
+
+#ifndef GL_SGIX_sprite
+#define GL_SGIX_sprite 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum, GLfloat);
+GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum, const GLfloat *);
+GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum, GLint);
+GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_SGIX_texture_multi_buffer
+#define GL_SGIX_texture_multi_buffer 1
+#endif
+
+#ifndef GL_EXT_point_parameters
+#define GL_EXT_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfEXT (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvEXT (GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_SGIS_point_parameters
+#define GL_SGIS_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfSGIS (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvSGIS (GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_SGIX_instruments
+#define GL_SGIX_instruments 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLint APIENTRY glGetInstrumentsSGIX (void);
+GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei, GLint *);
+GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *);
+GLAPI void APIENTRY glReadInstrumentsSGIX (GLint);
+GLAPI void APIENTRY glStartInstrumentsSGIX (void);
+GLAPI void APIENTRY glStopInstrumentsSGIX (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer);
+typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p);
+typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker);
+typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker);
+#endif
+
+#ifndef GL_SGIX_texture_scale_bias
+#define GL_SGIX_texture_scale_bias 1
+#endif
+
+#ifndef GL_SGIX_framezoom
+#define GL_SGIX_framezoom 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFrameZoomSGIX (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor);
+#endif
+
+#ifndef GL_SGIX_tag_sample_buffer
+#define GL_SGIX_tag_sample_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTagSampleBufferSGIX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void);
+#endif
+
+#ifndef GL_SGIX_polynomial_ffd
+#define GL_SGIX_polynomial_ffd 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble *);
+GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat *);
+GLAPI void APIENTRY glDeformSGIX (GLbitfield);
+GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points);
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points);
+typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask);
+#endif
+
+#ifndef GL_SGIX_reference_plane
+#define GL_SGIX_reference_plane 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation);
+#endif
+
+#ifndef GL_SGIX_flush_raster
+#define GL_SGIX_flush_raster 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushRasterSGIX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void);
+#endif
+
+#ifndef GL_SGIX_depth_texture
+#define GL_SGIX_depth_texture 1
+#endif
+
+#ifndef GL_SGIS_fog_function
+#define GL_SGIS_fog_function 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogFuncSGIS (GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points);
+#endif
+
+#ifndef GL_SGIX_fog_offset
+#define GL_SGIX_fog_offset 1
+#endif
+
+#ifndef GL_HP_image_transform
+#define GL_HP_image_transform 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glImageTransformParameteriHP (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glImageTransformParameterfHP (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glImageTransformParameterivHP (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_HP_convolution_border_modes
+#define GL_HP_convolution_border_modes 1
+#endif
+
+#ifndef GL_SGIX_texture_add_env
+#define GL_SGIX_texture_add_env 1
+#endif
+
+#ifndef GL_EXT_color_subtable
+#define GL_EXT_color_subtable 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorSubTableEXT (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum, GLsizei, GLint, GLint, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+#endif
+
+#ifndef GL_PGI_vertex_hints
+#define GL_PGI_vertex_hints 1
+#endif
+
+#ifndef GL_PGI_misc_hints
+#define GL_PGI_misc_hints 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glHintPGI (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode);
+#endif
+
+#ifndef GL_EXT_paletted_texture
+#define GL_EXT_paletted_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glGetColorTableEXT (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_EXT_clip_volume_hint
+#define GL_EXT_clip_volume_hint 1
+#endif
+
+#ifndef GL_SGIX_list_priority
+#define GL_SGIX_list_priority 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetListParameterivSGIX (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glListParameterfSGIX (GLuint, GLenum, GLfloat);
+GLAPI void APIENTRY glListParameterfvSGIX (GLuint, GLenum, const GLfloat *);
+GLAPI void APIENTRY glListParameteriSGIX (GLuint, GLenum, GLint);
+GLAPI void APIENTRY glListParameterivSGIX (GLuint, GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_SGIX_ir_instrument1
+#define GL_SGIX_ir_instrument1 1
+#endif
+
+#ifndef GL_SGIX_calligraphic_fragment
+#define GL_SGIX_calligraphic_fragment 1
+#endif
+
+#ifndef GL_SGIX_texture_lod_bias
+#define GL_SGIX_texture_lod_bias 1
+#endif
+
+#ifndef GL_SGIX_shadow_ambient
+#define GL_SGIX_shadow_ambient 1
+#endif
+
+#ifndef GL_EXT_index_texture
+#define GL_EXT_index_texture 1
+#endif
+
+#ifndef GL_EXT_index_material
+#define GL_EXT_index_material 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexMaterialEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode);
+#endif
+
+#ifndef GL_EXT_index_func
+#define GL_EXT_index_func 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexFuncEXT (GLenum, GLclampf);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref);
+#endif
+
+#ifndef GL_EXT_index_array_formats
+#define GL_EXT_index_array_formats 1
+#endif
+
+#ifndef GL_EXT_compiled_vertex_array
+#define GL_EXT_compiled_vertex_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLockArraysEXT (GLint, GLsizei);
+GLAPI void APIENTRY glUnlockArraysEXT (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void);
+#endif
+
+#ifndef GL_EXT_cull_vertex
+#define GL_EXT_cull_vertex 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCullParameterdvEXT (GLenum, GLdouble *);
+GLAPI void APIENTRY glCullParameterfvEXT (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_SGIX_ycrcb
+#define GL_SGIX_ycrcb 1
+#endif
+
+#ifndef GL_SGIX_fragment_lighting
+#define GL_SGIX_fragment_lighting 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum, GLenum);
+GLAPI void APIENTRY glFragmentLightfSGIX (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentLightiSGIX (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glFragmentLightivSGIX (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum, GLint);
+GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum, const GLint *);
+GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glLightEnviSGIX (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param);
+#endif
+
+#ifndef GL_IBM_rasterpos_clip
+#define GL_IBM_rasterpos_clip 1
+#endif
+
+#ifndef GL_HP_texture_lighting
+#define GL_HP_texture_lighting 1
+#endif
+
+#ifndef GL_EXT_draw_range_elements
+#define GL_EXT_draw_range_elements 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+#endif
+
+#ifndef GL_WIN_phong_shading
+#define GL_WIN_phong_shading 1
+#endif
+
+#ifndef GL_WIN_specular_fog
+#define GL_WIN_specular_fog 1
+#endif
+
+#ifndef GL_EXT_light_texture
+#define GL_EXT_light_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glApplyTextureEXT (GLenum);
+GLAPI void APIENTRY glTextureLightEXT (GLenum);
+GLAPI void APIENTRY glTextureMaterialEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode);
+#endif
+
+#ifndef GL_SGIX_blend_alpha_minmax
+#define GL_SGIX_blend_alpha_minmax 1
+#endif
+
+#ifndef GL_EXT_bgra
+#define GL_EXT_bgra 1
+#endif
+
+#ifndef GL_SGIX_async
+#define GL_SGIX_async 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint);
+GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *);
+GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *);
+GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei);
+GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint, GLsizei);
+GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker);
+typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp);
+typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp);
+typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range);
+typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range);
+typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker);
+#endif
+
+#ifndef GL_SGIX_async_pixel
+#define GL_SGIX_async_pixel 1
+#endif
+
+#ifndef GL_SGIX_async_histogram
+#define GL_SGIX_async_histogram 1
+#endif
+
+#ifndef GL_INTEL_parallel_arrays
+#define GL_INTEL_parallel_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexPointervINTEL (GLint, GLenum, const GLvoid* *);
+GLAPI void APIENTRY glNormalPointervINTEL (GLenum, const GLvoid* *);
+GLAPI void APIENTRY glColorPointervINTEL (GLint, GLenum, const GLvoid* *);
+GLAPI void APIENTRY glTexCoordPointervINTEL (GLint, GLenum, const GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+#endif
+
+#ifndef GL_HP_occlusion_test
+#define GL_HP_occlusion_test 1
+#endif
+
+#ifndef GL_EXT_pixel_transform
+#define GL_EXT_pixel_transform 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum, GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_EXT_pixel_transform_color_table
+#define GL_EXT_pixel_transform_color_table 1
+#endif
+
+#ifndef GL_EXT_shared_texture_palette
+#define GL_EXT_shared_texture_palette 1
+#endif
+
+#ifndef GL_EXT_separate_specular_color
+#define GL_EXT_separate_specular_color 1
+#endif
+
+#ifndef GL_EXT_secondary_color
+#define GL_EXT_secondary_color 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glSecondaryColor3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *);
+GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *);
+GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *);
+GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *);
+GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort, GLushort, GLushort);
+GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *);
+GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_texture_perturb_normal
+#define GL_EXT_texture_perturb_normal 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureNormalEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode);
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+#endif
+
+#ifndef GL_EXT_fog_coord
+#define GL_EXT_fog_coord 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogCoordfEXT (GLfloat);
+GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *);
+GLAPI void APIENTRY glFogCoorddEXT (GLdouble);
+GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *);
+GLAPI void APIENTRY glFogCoordPointerEXT (GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_REND_screen_coordinates
+#define GL_REND_screen_coordinates 1
+#endif
+
+#ifndef GL_EXT_coordinate_frame
+#define GL_EXT_coordinate_frame 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTangent3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glTangent3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glTangent3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glTangent3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glTangent3ivEXT (const GLint *);
+GLAPI void APIENTRY glTangent3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glTangent3svEXT (const GLshort *);
+GLAPI void APIENTRY glBinormal3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glBinormal3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glBinormal3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glBinormal3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glBinormal3ivEXT (const GLint *);
+GLAPI void APIENTRY glBinormal3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glBinormal3svEXT (const GLshort *);
+GLAPI void APIENTRY glTangentPointerEXT (GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glBinormalPointerEXT (GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz);
+typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz);
+typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz);
+typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz);
+typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz);
+typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz);
+typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz);
+typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz);
+typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz);
+typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz);
+typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_texture_env_combine
+#define GL_EXT_texture_env_combine 1
+#endif
+
+#ifndef GL_APPLE_specular_vector
+#define GL_APPLE_specular_vector 1
+#endif
+
+#ifndef GL_APPLE_transform_hint
+#define GL_APPLE_transform_hint 1
+#endif
+
+#ifndef GL_SGIX_fog_scale
+#define GL_SGIX_fog_scale 1
+#endif
+
+#ifndef GL_SUNX_constant_data
+#define GL_SUNX_constant_data 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFinishTextureSUNX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void);
+#endif
+
+#ifndef GL_SUN_global_alpha
+#define GL_SUN_global_alpha 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte);
+GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort);
+GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint);
+GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat);
+GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble);
+GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte);
+GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort);
+GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor);
+#endif
+
+#ifndef GL_SUN_triangle_list
+#define GL_SUN_triangle_list 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint);
+GLAPI void APIENTRY glReplacementCodeusSUN (GLushort);
+GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte);
+GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *);
+GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *);
+GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *);
+GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum, GLsizei, const GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid* *pointer);
+#endif
+
+#ifndef GL_SUN_vertex
+#define GL_SUN_vertex 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat, GLfloat, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+#endif
+
+#ifndef GL_EXT_blend_func_separate
+#define GL_EXT_blend_func_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum, GLenum, GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+
+#ifndef GL_INGR_blend_func_separate
+#define GL_INGR_blend_func_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum, GLenum, GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+
+#ifndef GL_INGR_color_clamp
+#define GL_INGR_color_clamp 1
+#endif
+
+#ifndef GL_INGR_interlace_read
+#define GL_INGR_interlace_read 1
+#endif
+
+#ifndef GL_EXT_stencil_wrap
+#define GL_EXT_stencil_wrap 1
+#endif
+
+#ifndef GL_EXT_422_pixels
+#define GL_EXT_422_pixels 1
+#endif
+
+#ifndef GL_NV_texgen_reflection
+#define GL_NV_texgen_reflection 1
+#endif
+
+#ifndef GL_SUN_convolution_border_modes
+#define GL_SUN_convolution_border_modes 1
+#endif
+
+#ifndef GL_EXT_texture_env_add
+#define GL_EXT_texture_env_add 1
+#endif
+
+#ifndef GL_EXT_texture_lod_bias
+#define GL_EXT_texture_lod_bias 1
+#endif
+
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+#ifndef GL_EXT_vertex_weighting
+#define GL_EXT_vertex_weighting 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexWeightfEXT (GLfloat);
+GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *);
+GLAPI void APIENTRY glVertexWeightPointerEXT (GLsizei, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_NV_light_max_exponent
+#define GL_NV_light_max_exponent 1
+#endif
+
+#ifndef GL_NV_vertex_array_range
+#define GL_NV_vertex_array_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushVertexArrayRangeNV (void);
+GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void);
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer);
+#endif
+
+#ifndef GL_NV_register_combiners
+#define GL_NV_register_combiners 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerParameterfvNV (GLenum, const GLfloat *);
+GLAPI void APIENTRY glCombinerParameterfNV (GLenum, GLfloat);
+GLAPI void APIENTRY glCombinerParameterivNV (GLenum, const GLint *);
+GLAPI void APIENTRY glCombinerParameteriNV (GLenum, GLint);
+GLAPI void APIENTRY glCombinerInputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glCombinerOutputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLboolean, GLboolean, GLboolean);
+GLAPI void APIENTRY glFinalCombinerInputNV (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum, GLenum, GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum, GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum, GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);
+typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_NV_fog_distance
+#define GL_NV_fog_distance 1
+#endif
+
+#ifndef GL_NV_texgen_emboss
+#define GL_NV_texgen_emboss 1
+#endif
+
+#ifndef GL_NV_blend_square
+#define GL_NV_blend_square 1
+#endif
+
+#ifndef GL_NV_texture_env_combine4
+#define GL_NV_texture_env_combine4 1
+#endif
+
+#ifndef GL_MESA_resize_buffers
+#define GL_MESA_resize_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glResizeBuffersMESA (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void);
+#endif
+
+#ifndef GL_MESA_window_pos
+#define GL_MESA_window_pos 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dMESA (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2fMESA (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2iMESA (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos2sMESA (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *);
+GLAPI void APIENTRY glWindowPos3dMESA (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3fMESA (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3iMESA (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos3sMESA (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *);
+GLAPI void APIENTRY glWindowPos4dMESA (GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos4fMESA (GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos4iMESA (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos4sMESA (GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_IBM_cull_vertex
+#define GL_IBM_cull_vertex 1
+#endif
+
+#ifndef GL_IBM_multimode_draw_arrays
+#define GL_IBM_multimode_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *, const GLint *, const GLsizei *, GLsizei, GLint);
+GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *, const GLsizei *, GLenum, const GLvoid* const *, GLsizei, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride);
+#endif
+
+#ifndef GL_IBM_vertex_array_lists
+#define GL_IBM_vertex_array_lists 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint, const GLboolean* *, GLint);
+GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glIndexPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glNormalPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glTexCoordPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glVertexPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+#endif
+
+#ifndef GL_SGIX_subsample
+#define GL_SGIX_subsample 1
+#endif
+
+#ifndef GL_SGIX_ycrcba
+#define GL_SGIX_ycrcba 1
+#endif
+
+#ifndef GL_SGIX_ycrcb_subsample
+#define GL_SGIX_ycrcb_subsample 1
+#endif
+
+#ifndef GL_SGIX_depth_pass_instrument
+#define GL_SGIX_depth_pass_instrument 1
+#endif
+
+#ifndef GL_3DFX_texture_compression_FXT1
+#define GL_3DFX_texture_compression_FXT1 1
+#endif
+
+#ifndef GL_3DFX_multisample
+#define GL_3DFX_multisample 1
+#endif
+
+#ifndef GL_3DFX_tbuffer
+#define GL_3DFX_tbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTbufferMask3DFX (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask);
+#endif
+
+#ifndef GL_EXT_multisample
+#define GL_EXT_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskEXT (GLclampf, GLboolean);
+GLAPI void APIENTRY glSamplePatternEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern);
+#endif
+
+#ifndef GL_SGIX_vertex_preclip
+#define GL_SGIX_vertex_preclip 1
+#endif
+
+#ifndef GL_SGIX_convolution_accuracy
+#define GL_SGIX_convolution_accuracy 1
+#endif
+
+#ifndef GL_SGIX_resample
+#define GL_SGIX_resample 1
+#endif
+
+#ifndef GL_SGIS_point_line_texgen
+#define GL_SGIS_point_line_texgen 1
+#endif
+
+#ifndef GL_SGIS_texture_color_mask
+#define GL_SGIS_texture_color_mask 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean, GLboolean, GLboolean, GLboolean);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+#endif
+
+#ifndef GL_SGIX_igloo_interface
+#define GL_SGIX_igloo_interface 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params);
+#endif
+
+#ifndef GL_EXT_texture_env_dot3
+#define GL_EXT_texture_env_dot3 1
+#endif
+
+#ifndef GL_ATI_texture_mirror_once
+#define GL_ATI_texture_mirror_once 1
+#endif
+
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenFencesNV (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsFenceNV (GLuint);
+GLAPI GLboolean APIENTRY glTestFenceNV (GLuint);
+GLAPI void APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glFinishFenceNV (GLuint);
+GLAPI void APIENTRY glSetFenceNV (GLuint, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+#ifndef GL_NV_evaluators
+#define GL_NV_evaluators 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLint, GLint, GLboolean, const GLvoid *);
+GLAPI void APIENTRY glMapParameterivNV (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glMapParameterfvNV (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLboolean, GLvoid *);
+GLAPI void APIENTRY glGetMapParameterivNV (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMapParameterfvNV (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum, GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum, GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glEvalMapsNV (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points);
+typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode);
+#endif
+
+#ifndef GL_NV_packed_depth_stencil
+#define GL_NV_packed_depth_stencil 1
+#endif
+
+#ifndef GL_NV_register_combiners2
+#define GL_NV_register_combiners2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_NV_texture_compression_vtc
+#define GL_NV_texture_compression_vtc 1
+#endif
+
+#ifndef GL_NV_texture_rectangle
+#define GL_NV_texture_rectangle 1
+#endif
+
+#ifndef GL_NV_texture_shader
+#define GL_NV_texture_shader 1
+#endif
+
+#ifndef GL_NV_texture_shader2
+#define GL_NV_texture_shader2 1
+#endif
+
+#ifndef GL_NV_vertex_array_range2
+#define GL_NV_vertex_array_range2 1
+#endif
+
+#ifndef GL_NV_vertex_program
+#define GL_NV_vertex_program 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei, const GLuint *, GLboolean *);
+GLAPI void APIENTRY glBindProgramNV (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteProgramsNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glExecuteProgramNV (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glGenProgramsNV (GLsizei, GLuint *);
+GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum, GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum, GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetProgramivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramStringNV (GLuint, GLenum, GLubyte *);
+GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum, GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgramNV (GLuint);
+GLAPI void APIENTRY glLoadProgramNV (GLenum, GLuint, GLsizei, const GLubyte *);
+GLAPI void APIENTRY glProgramParameter4dNV (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramParameter4dvNV (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramParameter4fNV (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramParameter4fvNV (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glProgramParameters4dvNV (GLenum, GLuint, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramParameters4fvNV (GLenum, GLuint, GLuint, const GLfloat *);
+GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glTrackMatrixNV (GLenum, GLuint, GLenum, GLenum);
+GLAPI void APIENTRY glVertexAttribPointerNV (GLuint, GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexAttrib1dNV (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1fNV (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1sNV (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2dNV (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2fNV (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2sNV (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3dNV (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3fNV (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3sNV (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4dNV (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4fNV (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4sNV (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs1svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs2svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs3svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs4svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint, GLsizei, const GLubyte *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program);
+typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLuint count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLuint count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v);
+#endif
+
+#ifndef GL_SGIX_texture_coordinate_clamp
+#define GL_SGIX_texture_coordinate_clamp 1
+#endif
+
+#ifndef GL_SGIX_scalebias_hint
+#define GL_SGIX_scalebias_hint 1
+#endif
+
+#ifndef GL_OML_interlace
+#define GL_OML_interlace 1
+#endif
+
+#ifndef GL_OML_subsample
+#define GL_OML_subsample 1
+#endif
+
+#ifndef GL_OML_resample
+#define GL_OML_resample 1
+#endif
+
+#ifndef GL_NV_copy_depth_to_color
+#define GL_NV_copy_depth_to_color 1
+#endif
+
+#ifndef GL_ATI_envmap_bumpmap
+#define GL_ATI_envmap_bumpmap 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexBumpParameterivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum, GLint *);
+GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param);
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param);
+#endif
+
+#ifndef GL_ATI_fragment_shader
+#define GL_ATI_fragment_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint);
+GLAPI void APIENTRY glBindFragmentShaderATI (GLuint);
+GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint);
+GLAPI void APIENTRY glBeginFragmentShaderATI (void);
+GLAPI void APIENTRY glEndFragmentShaderATI (void);
+GLAPI void APIENTRY glPassTexCoordATI (GLuint, GLuint, GLenum);
+GLAPI void APIENTRY glSampleMapATI (GLuint, GLuint, GLenum);
+GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle);
+typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value);
+#endif
+
+#ifndef GL_ATI_pn_triangles
+#define GL_ATI_pn_triangles 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPNTrianglesiATI (GLenum, GLint);
+GLAPI void APIENTRY glPNTrianglesfATI (GLenum, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param);
+#endif
+
+#ifndef GL_ATI_vertex_array_object
+#define GL_ATI_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei, const GLvoid *, GLenum);
+GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint);
+GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint, GLuint, GLsizei, const GLvoid *, GLenum);
+GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetObjectBufferivATI (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glFreeObjectBufferATI (GLuint);
+GLAPI void APIENTRY glArrayObjectATI (GLenum, GLint, GLenum, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetArrayObjectivATI (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glVariantArrayObjectATI (GLuint, GLenum, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage);
+typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_EXT_vertex_shader
+#define GL_EXT_vertex_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginVertexShaderEXT (void);
+GLAPI void APIENTRY glEndVertexShaderEXT (void);
+GLAPI void APIENTRY glBindVertexShaderEXT (GLuint);
+GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint);
+GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint);
+GLAPI void APIENTRY glShaderOp1EXT (GLenum, GLuint, GLuint);
+GLAPI void APIENTRY glShaderOp2EXT (GLenum, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glShaderOp3EXT (GLenum, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSwizzleEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glWriteMaskEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glInsertComponentEXT (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glExtractComponentEXT (GLuint, GLuint, GLuint);
+GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum, GLenum, GLenum, GLuint);
+GLAPI void APIENTRY glSetInvariantEXT (GLuint, GLenum, const GLvoid *);
+GLAPI void APIENTRY glSetLocalConstantEXT (GLuint, GLenum, const GLvoid *);
+GLAPI void APIENTRY glVariantbvEXT (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVariantsvEXT (GLuint, const GLshort *);
+GLAPI void APIENTRY glVariantivEXT (GLuint, const GLint *);
+GLAPI void APIENTRY glVariantfvEXT (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVariantdvEXT (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVariantubvEXT (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVariantusvEXT (GLuint, const GLushort *);
+GLAPI void APIENTRY glVariantuivEXT (GLuint, const GLuint *);
+GLAPI void APIENTRY glVariantPointerEXT (GLuint, GLenum, GLuint, const GLvoid *);
+GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint);
+GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint);
+GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum, GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindParameterEXT (GLenum);
+GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint, GLenum);
+GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVariantPointervEXT (GLuint, GLenum, GLvoid* *);
+GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1);
+typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2);
+typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);
+typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components);
+typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr);
+typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr);
+typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr);
+typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr);
+typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr);
+typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr);
+typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value);
+typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap);
+typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid* *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+#endif
+
+#ifndef GL_ATI_vertex_streams
+#define GL_ATI_vertex_streams 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexStream1sATI (GLenum, GLshort);
+GLAPI void APIENTRY glVertexStream1svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream1iATI (GLenum, GLint);
+GLAPI void APIENTRY glVertexStream1ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream1fATI (GLenum, GLfloat);
+GLAPI void APIENTRY glVertexStream1fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream1dATI (GLenum, GLdouble);
+GLAPI void APIENTRY glVertexStream1dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream2sATI (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream2svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream2iATI (GLenum, GLint, GLint);
+GLAPI void APIENTRY glVertexStream2ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream2fATI (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream2fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream2dATI (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream2dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream3sATI (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream3svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream3iATI (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glVertexStream3ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream3fATI (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream3fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream3dATI (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream3dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream4sATI (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream4svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream4iATI (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glVertexStream4ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream4fATI (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream4fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream4dATI (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream4dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glNormalStream3bATI (GLenum, GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glNormalStream3bvATI (GLenum, const GLbyte *);
+GLAPI void APIENTRY glNormalStream3sATI (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glNormalStream3svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glNormalStream3iATI (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glNormalStream3ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glNormalStream3fATI (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glNormalStream3fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glNormalStream3dATI (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glNormalStream3dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum);
+GLAPI void APIENTRY glVertexBlendEnviATI (GLenum, GLint);
+GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param);
+#endif
+
+#ifndef GL_ATI_element_array
+#define GL_ATI_element_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerATI (GLenum, const GLvoid *);
+GLAPI void APIENTRY glDrawElementArrayATI (GLenum, GLsizei);
+GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum, GLuint, GLuint, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count);
+#endif
+
+#ifndef GL_SUN_mesh_array
+#define GL_SUN_mesh_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width);
+#endif
+
+#ifndef GL_SUN_slice_accum
+#define GL_SUN_slice_accum 1
+#endif
+
+#ifndef GL_NV_multisample_filter_hint
+#define GL_NV_multisample_filter_hint 1
+#endif
+
+#ifndef GL_NV_depth_clamp
+#define GL_NV_depth_clamp 1
+#endif
+
+#ifndef GL_NV_occlusion_query
+#define GL_NV_occlusion_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint);
+GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint);
+GLAPI void APIENTRY glEndOcclusionQueryNV (void);
+GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint, GLenum, GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
+#ifndef GL_NV_point_sprite
+#define GL_NV_point_sprite 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameteriNV (GLenum, GLint);
+GLAPI void APIENTRY glPointParameterivNV (GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_NV_texture_shader3
+#define GL_NV_texture_shader3 1
+#endif
+
+#ifndef GL_NV_vertex_program1_1
+#define GL_NV_vertex_program1_1 1
+#endif
+
+#ifndef GL_EXT_shadow_funcs
+#define GL_EXT_shadow_funcs 1
+#endif
+
+#ifndef GL_EXT_stencil_two_side
+#define GL_EXT_stencil_two_side 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
+#endif
+
+#ifndef GL_ATI_text_fragment_shader
+#define GL_ATI_text_fragment_shader 1
+#endif
+
+#ifndef GL_APPLE_client_storage
+#define GL_APPLE_client_storage 1
+#endif
+
+#ifndef GL_APPLE_element_array
+#define GL_APPLE_element_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerAPPLE (GLenum, const GLvoid *);
+GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum, GLint, GLsizei);
+GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, GLint, GLsizei);
+GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum, const GLint *, const GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, const GLint *, const GLsizei *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount);
+#endif
+
+#ifndef GL_APPLE_fence
+#define GL_APPLE_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenFencesAPPLE (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei, const GLuint *);
+GLAPI void APIENTRY glSetFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint);
+GLAPI void APIENTRY glFinishFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum, GLuint);
+GLAPI void APIENTRY glFinishObjectAPPLE (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences);
+typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name);
+typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name);
+#endif
+
+#ifndef GL_APPLE_vertex_array_object
+#define GL_APPLE_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint);
+GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array);
+typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);
+#endif
+
+#ifndef GL_APPLE_vertex_array_range
+#define GL_APPLE_vertex_array_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei, GLvoid *);
+GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei, GLvoid *);
+GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param);
+#endif
+
+#ifndef GL_APPLE_ycbcr_422
+#define GL_APPLE_ycbcr_422 1
+#endif
+
+#ifndef GL_S3_s3tc
+#define GL_S3_s3tc 1
+#endif
+
+#ifndef GL_ATI_draw_buffers
+#define GL_ATI_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersATI (GLsizei, const GLenum *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+#ifndef GL_ATI_pixel_format_float
+#define GL_ATI_pixel_format_float 1
+/* This is really a WGL extension, but defines some associated GL enums.
+ * ATI does not export "GL_ATI_pixel_format_float" in the GL_EXTENSIONS string.
+ */
+#endif
+
+#ifndef GL_ATI_texture_env_combine3
+#define GL_ATI_texture_env_combine3 1
+#endif
+
+#ifndef GL_ATI_texture_float
+#define GL_ATI_texture_float 1
+#endif
+
+#ifndef GL_NV_float_buffer
+#define GL_NV_float_buffer 1
+#endif
+
+#ifndef GL_NV_fragment_program
+#define GL_NV_fragment_program 1
+/* Some NV_fragment_program entry points are shared with ARB_vertex_program. */
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint, GLsizei, const GLubyte *, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint, GLsizei, const GLubyte *, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint, GLsizei, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint, GLsizei, const GLubyte *, const GLdouble *);
+GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint, GLsizei, const GLubyte *, GLfloat *);
+GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint, GLsizei, const GLubyte *, GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params);
+#endif
+
+#ifndef GL_NV_half_float
+#define GL_NV_half_float 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertex2hNV (GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertex3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertex4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glNormal3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glColor4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV);
+GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glFogCoordhNV (GLhalfNV);
+GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *);
+GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV);
+GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib1hNV (GLuint, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib2hNV (GLuint, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib3hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib4hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint, GLsizei, const GLhalfNV *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz);
+typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha);
+typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s);
+typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);
+typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+#endif
+
+#ifndef GL_NV_pixel_data_range
+#define GL_NV_pixel_data_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelDataRangeNV (GLenum, GLsizei, GLvoid *);
+GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target);
+#endif
+
+#ifndef GL_NV_primitive_restart
+#define GL_NV_primitive_restart 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPrimitiveRestartNV (void);
+GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void);
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index);
+#endif
+
+#ifndef GL_NV_texture_expand_normal
+#define GL_NV_texture_expand_normal 1
+#endif
+
+#ifndef GL_NV_vertex_program2
+#define GL_NV_vertex_program2 1
+#endif
+
+#ifndef GL_ATI_map_object_buffer
+#define GL_ATI_map_object_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLvoid* APIENTRY glMapObjectBufferATI (GLuint);
+GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLvoid* (APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+#endif
+
+#ifndef GL_ATI_separate_stencil
+#define GL_ATI_separate_stencil 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStencilOpSeparateATI (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum, GLenum, GLint, GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+#endif
+
+#ifndef GL_ATI_vertex_attrib_array_object
+#define GL_ATI_vertex_attrib_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint, GLint, GLenum, GLboolean, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_OES_read_format
+#define GL_OES_read_format 1
+#endif
+
+#ifndef GL_EXT_depth_bounds_test
+#define GL_EXT_depth_bounds_test 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDepthBoundsEXT (GLclampd, GLclampd);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax);
+#endif
+
+#ifndef GL_EXT_texture_mirror_clamp
+#define GL_EXT_texture_mirror_clamp 1
+#endif
+
+#ifndef GL_EXT_blend_equation_separate
+#define GL_EXT_blend_equation_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha);
+#endif
+
+#ifndef GL_MESA_pack_invert
+#define GL_MESA_pack_invert 1
+#endif
+
+#ifndef GL_MESA_ycbcr_texture
+#define GL_MESA_ycbcr_texture 1
+#endif
+
+#ifndef GL_EXT_pixel_buffer_object
+#define GL_EXT_pixel_buffer_object 1
+#endif
+
+#ifndef GL_NV_fragment_program_option
+#define GL_NV_fragment_program_option 1
+#endif
+
+#ifndef GL_NV_fragment_program2
+#define GL_NV_fragment_program2 1
+#endif
+
+#ifndef GL_NV_vertex_program2_option
+#define GL_NV_vertex_program2_option 1
+#endif
+
+#ifndef GL_NV_vertex_program3
+#define GL_NV_vertex_program3 1
+#endif
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_EXT_framebuffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint);
+GLAPI void APIENTRY glBindRenderbufferEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei, GLuint *);
+GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum, GLenum, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint);
+GLAPI void APIENTRY glBindFramebufferEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei, GLuint *);
+GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum);
+GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum, GLenum, GLenum, GLuint, GLint);
+GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum, GLenum, GLenum, GLuint, GLint);
+GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLint);
+GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum, GLenum, GLenum, GLuint);
+GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGenerateMipmapEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer);
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target);
+#endif
+
+#ifndef GL_GREMEDY_string_marker
+#define GL_GREMEDY_string_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/mkglext.py b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/mkglext.py
new file mode 100644
index 00000000000..8e64ecd1741
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/mkglext.py
@@ -0,0 +1,630 @@
+#!/usr/bin/python
+#
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+#
+# mkglext.py generates code for linking extensions.
+#
+# It reads the glext.h header from stdin and writes code to stdout.
+#
+# Usage: mkglext.py < glext.h > tmp
+# Code can be copied & pasted from tmp to GL_ExtensionManager.cpp.
+#
+# glext.h is available here: http://oss.sgi.com/projects/ogl-sample/ABI/glext.h
+#
+
+from sys import stdin
+import string, re
+
+glext_h = string.split(stdin.read(), '\n')
+
+# These extensions have been incorporated into the core GL or been superceded.
+# Code will not be generated for these extensions
+blacklist = [
+ "GL_EXT_multisample",
+ "GL_INGR_blend_func_separate",
+ "GL_SGIX_fragment_lighting",
+ "GL_SGIX_polynomial_ffd",
+ "GL_SGIS_point_parameters",
+ "GL_EXT_texture_object",
+ "GL_EXT_subtexture",
+ "GL_EXT_copy_texture",
+ "GL_EXT_vertex_array",
+ "GL_EXT_point_parameters",
+ "GL_EXT_blend_color",
+ "GL_EXT_polygon_offset",
+ "GL_EXT_texture"]
+
+# Only code for these extensions will be generated. Extensions on both the
+# blacklist & whitelist will not have code generated.
+# This list is from http://oss.sgi.com/projects/ogl-sample/registry/ at 14-Mar-04
+whitelist = [
+ # ARB Extensions
+ "GL_ARB_multitexture",
+ "GLX_ARB_get_proc_address",
+ "GL_ARB_transpose_matrix",
+ "WGL_ARB_buffer_region",
+ "GL_ARB_multisample",
+ "GL_ARB_texture_env_add",
+ "GL_ARB_texture_cube_map",
+ "WGL_ARB_extensions_string",
+ "WGL_ARB_pixel_format",
+ "WGL_ARB_make_current_read",
+ "WGL_ARB_pbuffer",
+ "GL_ARB_texture_compression",
+ "GL_ARB_texture_border_clamp",
+ "GL_ARB_point_parameters",
+ "GL_ARB_vertex_blend",
+ "GL_ARB_matrix_palette",
+ "GL_ARB_texture_env_combine",
+ "GL_ARB_texture_env_crossbar",
+ "GL_ARB_texture_env_dot3",
+ "WGL_ARB_render_texture",
+ "GL_ARB_texture_mirrored_repeat",
+ "GL_ARB_depth_texture",
+ "GL_ARB_shadow",
+ "GL_ARB_shadow_ambient",
+ "GL_ARB_window_pos",
+ "GL_ARB_vertex_program",
+ "GL_ARB_fragment_program",
+ "GL_ARB_vertex_buffer_object",
+ "GL_ARB_occlusion_query",
+ "GL_ARB_shader_objects",
+ "GL_ARB_vertex_shader",
+ "GL_ARB_fragment_shader",
+ "GL_ARB_shading_language_100",
+ "GL_ARB_texture_non_power_of_two",
+ "GL_ARB_point_sprite",
+ "GL_ARB_fragment_program_shadow",
+
+ # Non ARB Extensions
+ "GL_EXT_abgr",
+ "GL_EXT_blend_color",
+ "GL_EXT_polygon_offset",
+ "GL_EXT_texture",
+ "GL_EXT_texture3D",
+ "GL_SGIS_texture_filter4",
+ "GL_EXT_subtexture",
+ "GL_EXT_copy_texture",
+ "GL_EXT_histogram",
+ "GL_EXT_convolution",
+ "GL_SGI_color_matrix",
+ "GL_SGI_color_table",
+ "GL_SGIS_pixel_texture",
+ "GL_SGIS_texture4D",
+ "GL_SGI_texture_color_table",
+ "GL_EXT_cmyka",
+ "GL_EXT_texture_object",
+ "GL_SGIS_detail_texture",
+ "GL_SGIS_sharpen_texture",
+ "GL_EXT_packed_pixels",
+ "GL_SGIS_texture_lod",
+ "GL_SGIS_multisample",
+ "GL_EXT_rescale_normal",
+ "GLX_EXT_visual_info",
+ "GL_EXT_vertex_array",
+ "GL_EXT_misc_attribute",
+ "GL_SGIS_generate_mipmap",
+ "GL_SGIX_clipmap",
+ "GL_SGIX_shadow",
+ "GL_SGIS_texture_edge_clamp",
+ "GL_SGIS_texture_border_clamp",
+ "GL_EXT_blend_minmax",
+ "GL_EXT_blend_subtract",
+ "GL_EXT_blend_logic_op",
+ "GLX_SGI_swap_control",
+ "GLX_SGI_video_sync",
+ "GLX_SGI_make_current_read",
+ "GLX_SGIX_video_source",
+ "GLX_EXT_visual_rating",
+ "GL_SGIX_interlace",
+ "GLX_EXT_import_context",
+ "GLX_SGIX_fbconfig",
+ "GLX_SGIX_pbuffer",
+ "GL_SGIS_texture_select",
+ "GL_SGIX_sprite",
+ "GL_SGIX_texture_multi_buffer",
+ "GL_EXT_point_parameters",
+ "GL_SGIX_instruments",
+ "GL_SGIX_texture_scale_bias",
+ "GL_SGIX_framezoom",
+ "GL_SGIX_tag_sample_buffer",
+ "GL_SGIX_reference_plane",
+ "GL_SGIX_flush_raster",
+ "GLX_SGI_cushion",
+ "GL_SGIX_depth_texture",
+ "GL_SGIS_fog_function",
+ "GL_SGIX_fog_offset",
+ "GL_HP_image_transform",
+ "GL_HP_convolution_border_modes",
+ "GL_SGIX_texture_add_env",
+ "GL_EXT_color_subtable",
+ "GLU_EXT_object_space_tess",
+ "GL_PGI_vertex_hints",
+ "GL_PGI_misc_hints",
+ "GL_EXT_paletted_texture",
+ "GL_EXT_clip_volume_hint",
+ "GL_SGIX_list_priority",
+ "GL_SGIX_ir_instrument1",
+ "GLX_SGIX_video_resize",
+ "GL_SGIX_texture_lod_bias",
+ "GLU_SGI_filter4_parameters",
+ "GLX_SGIX_dm_buffer",
+ "GL_SGIX_shadow_ambient",
+ "GLX_SGIX_swap_group",
+ "GLX_SGIX_swap_barrier",
+ "GL_EXT_index_texture",
+ "GL_EXT_index_material",
+ "GL_EXT_index_func",
+ "GL_EXT_index_array_formats",
+ "GL_EXT_compiled_vertex_array",
+ "GL_EXT_cull_vertex",
+ "GLU_EXT_nurbs_tessellator",
+ "GL_SGIX_ycrcb",
+ "GL_EXT_fragment_lighting",
+ "GL_IBM_rasterpos_clip",
+ "GL_HP_texture_lighting",
+ "GL_EXT_draw_range_elements",
+ "GL_WIN_phong_shading",
+ "GL_WIN_specular_fog",
+ "GLX_SGIS_color_range",
+ "GL_EXT_light_texture",
+ "GL_SGIX_blend_alpha_minmax",
+ "GL_EXT_scene_marker",
+ "GL_SGIX_pixel_texture_bits",
+ "GL_EXT_bgra",
+ "GL_SGIX_async",
+ "GL_SGIX_async_pixel",
+ "GL_SGIX_async_histogram",
+ "GL_INTEL_texture_scissor",
+ "GL_INTEL_parallel_arrays",
+ "GL_HP_occlusion_test",
+ "GL_EXT_pixel_transform",
+ "GL_EXT_pixel_transform_color_table",
+ "GL_EXT_shared_texture_palette",
+ "GLX_SGIS_blended_overlay",
+ "GL_EXT_separate_specular_color",
+ "GL_EXT_secondary_color",
+ "GL_EXT_texture_env",
+ "GL_EXT_texture_perturb_normal",
+ "GL_EXT_multi_draw_arrays",
+ "GL_EXT_fog_coord",
+ "GL_REND_screen_coordinates",
+ "GL_EXT_coordinate_frame",
+ "GL_EXT_texture_env_combine",
+ "GL_APPLE_specular_vector",
+ "GL_SGIX_pixel_texture",
+ "GL_APPLE_transform_hint",
+ "GL_SUNX_constant_data",
+ "GL_SUN_global_alpha",
+ "GL_SUN_triangle_list",
+ "GL_SUN_vertex",
+ "WGL_EXT_display_color_table",
+ "WGL_EXT_extensions_string",
+ "WGL_EXT_make_current_read",
+ "WGL_EXT_pixel_format",
+ "WGL_EXT_pbuffer",
+ "WGL_EXT_swap_control",
+ "GL_EXT_blend_func_separate",
+ "GL_INGR_color_clamp",
+ "GL_INGR_interlace_read",
+ "GL_EXT_stencil_wrap",
+ "WGL_EXT_depth_float",
+ "GL_EXT_422_pixels",
+ "GL_NV_texgen_reflection",
+ "GL_SGIX_texture_range",
+ "GL_SUN_convolution_border_modes",
+ "GLX_SUN_get_transparent_index",
+ "GL_EXT_texture_env_add",
+ "GL_EXT_texture_lod_bias",
+ "GL_EXT_texture_filter_anisotropic",
+ "GL_EXT_vertex_weighting",
+ "GL_NV_light_max_exponent",
+ "GL_NV_vertex_array_range",
+ "GL_NV_register_combiners",
+ "GL_NV_fog_distance",
+ "GL_NV_texgen_emboss",
+ "GL_NV_blend_square",
+ "GL_NV_texture_env_combine4",
+ "GL_MESA_resize_buffers",
+ "GL_MESA_window_pos",
+ "GL_EXT_texture_compression_s3tc",
+ "GL_IBM_cull_vertex",
+ "GL_IBM_multimode_draw_arrays",
+ "GL_IBM_vertex_array_lists",
+ "GL_3DFX_texture_compression_FXT1",
+ "GL_3DFX_multisample",
+ "GL_3DFX_tbuffer",
+ "WGL_EXT_multisample",
+ "GL_SGIX_vertex_preclip",
+ "GL_SGIX_resample",
+ "GL_SGIS_texture_color_mask",
+ "GLX_MESA_copy_sub_buffer",
+ "GLX_MESA_pixmap_colormap",
+ "GLX_MESA_release_buffers",
+ "GLX_MESA_set_3dfx_mode",
+ "GL_EXT_texture_env_dot3",
+ "GL_ATI_texture_mirror_once",
+ "GL_NV_fence",
+ "GL_IBM_static_data",
+ "GL_IBM_texture_mirrored_repeat",
+ "GL_NV_evaluators",
+ "GL_NV_packed_depth_stencil",
+ "GL_NV_register_combiners2",
+ "GL_NV_texture_compression_vtc",
+ "GL_NV_texture_rectangle",
+ "GL_NV_texture_shader",
+ "GL_NV_texture_shader2",
+ "GL_NV_vertex_array_range2",
+ "GL_NV_vertex_program",
+ "GLX_SGIX_visual_select_group",
+ "GL_SGIX_texture_coordinate_clamp",
+ "GLX_OML_swap_method",
+ "GLX_OML_sync_control",
+ "GL_OML_interlace",
+ "GL_OML_subsample",
+ "GL_OML_resample",
+ "WGL_OML_sync_control",
+ "GL_NV_copy_depth_to_color",
+ "GL_ATI_envmap_bumpmap",
+ "GL_ATI_fragment_shader",
+ "GL_ATI_pn_triangles",
+ "GL_ATI_vertex_array_object",
+ "GL_EXT_vertex_shader",
+ "GL_ATI_vertex_streams",
+ "WGL_I3D_digital_video_control",
+ "WGL_I3D_gamma",
+ "WGL_I3D_genlock",
+ "WGL_I3D_image_buffer",
+ "WGL_I3D_swap_frame_lock",
+ "WGL_I3D_swap_frame_usage",
+ "GL_ATI_element_array",
+ "GL_SUN_mesh_array",
+ "GL_SUN_slice_accum",
+ "GL_NV_multisample_filter_hint",
+ "GL_NV_depth_clamp",
+ "GL_NV_occlusion_query",
+ "GL_NV_point_sprite",
+ "WGL_NV_render_depth_texture",
+ "WGL_NV_render_texture_rectangle",
+ "GL_NV_texture_shader3",
+ "GL_NV_vertex_program1_1",
+ "GL_EXT_shadow_funcs",
+ "GL_EXT_stencil_two_side",
+ "GL_ATI_text_fragment_shader",
+ "GL_APPLE_client_storage",
+ "GL_APPLE_element_array",
+ "GL_APPLE_fence",
+ "GL_APPLE_vertex_array_object",
+ "GL_APPLE_vertex_array_range",
+ "GL_APPLE_ycbcr_422",
+ "GL_S3_s3tc",
+ "GL_ATI_draw_buffers",
+ "WGL_ATI_pixel_format_float",
+ "GL_ATI_texture_env_combine3",
+ "GL_ATI_texture_float",
+ "GL_NV_float_buffer",
+ "GL_NV_fragment_program",
+ "GL_NV_half_float",
+ "GL_NV_pixel_data_range",
+ "GL_NV_primitive_restart",
+ "GL_NV_texture_expand_normal",
+ "GL_NV_vertex_program2",
+ "GL_ATI_map_object_buffer",
+ "GL_ATI_separate_stencil",
+ "GL_ATI_vertex_attrib_array_object",
+ "GL_OES_byte_coordinates",
+ "GL_OES_fixed_point",
+ "GL_OES_single_precision",
+ "GL_OES_compressed_paletted_texture",
+ "GL_OES_read_format",
+ "GL_OES_query_matrix",
+ "GL_EXT_depth_bounds_test",
+ "GL_EXT_texture_mirror_clamp",
+ "GL_EXT_blend_equation_separate",
+ "GL_MESA_pack_invert",
+ "GL_MESA_ycbcr_texture"]
+
+"""
+Example code output:
+#ifdef GL_EXT_compiled_vertex_array
+ if (QueryExtension("GL_EXT_compiled_vertex_array"))
+ {
+ glUnlockArraysEXT = reinterpret_cast<PFNGLUNLOCKARRAYSEXTPROC>(bglGetProcAddress((const GLubyte *) "glUnlockArraysEXT"));
+ glLockArraysEXT = reinterpret_cast<PFNGLLOCKARRAYSEXTPROC>(bglGetProcAddress((const GLubyte *) "glLockArraysEXT"));
+ if (glUnlockArraysEXT && glLockArraysEXT)
+ {
+ EnableExtension(_GL_EXT_compiled_vertex_array);
+ if (doDebugMessages)
+ std::cout << "Detected GL_EXT_compiled_vertex_array" << std::endl;
+ } else {
+ std::cout << "ERROR: GL_EXT_compiled_vertex_array implementation is broken!" << std::endl;
+ }
+ }
+#endif
+"""
+def writeext(ext, fnlist):
+ if (find(blacklist, ext)):
+ return
+ if (len(fnlist) == 0):
+ # This extension has no functions to detect - don't need to wrap in
+ # #ifdef GL_extension names
+ print "\tif (QueryExtension(\"" + ext + "\"))"
+ print "\t{"
+ print "\t\tEnableExtension(_" + ext + ");"
+ print "\t\tif (doDebugMessages)"
+ print "\t\t\tstd::cout << \"Detected " + ext + "\" << std::endl;"
+ print "\t}"
+ print
+ return
+ print "#if defined(" + ext + ")"
+ print "\tif (QueryExtension(\"" + ext + "\"))"
+ print "\t{"
+ for fn in fnlist:
+ print "\t\t" + fn[0] + " = reinterpret_cast<" + fn[1] + ">(bglGetProcAddress((const GLubyte *) \"" + fn[0] + "\"));"
+ errcheck = ""
+ for fn in fnlist:
+ if (errcheck == ""):
+ errcheck = fn[0]
+ else:
+ errcheck = errcheck + " && " + fn[0]
+ print "\t\tif (" + errcheck + ") {"
+ print "\t\t\tEnableExtension(_" + ext + ");"
+ print "\t\t\tif (doDebugMessages)"
+ print "\t\t\t\tstd::cout << \"Enabled " + ext + "\" << std::endl;"
+ print "\t\t} else {"
+ print "\t\t\tstd::cout << \"ERROR: " + ext + " implementation is broken!\" << std::endl;"
+ print "\t\t}"
+ print "\t}"
+ print "#endif"
+ print
+
+"""
+Example Output:
+#if defined(GL_EXT_compiled_vertex_array)
+PFNGLLOCKARRAYSEXTPROC glLockArraysEXT;
+PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT;
+#endif
+"""
+def writeproto(ext, fnlist):
+ if (find(blacklist, ext) or not find(whitelist, ext)):
+ return
+ print "#if defined(" + ext + ")"
+ for fn in fnlist:
+ print fn[1] + " " + fn[0] + ";"
+ print "#endif"
+ print
+
+"""
+#ifdef GL_EXT_compiled_vertex_array
+extern PFNGLLOCKARRAYSEXTPROC glLockArraysEXT;
+extern PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT;
+#endif
+"""
+def writeheader(ext, fnlisti):
+ if (find(blacklist, ext) or not find(whitelist, ext)):
+ return
+ print "#if defined(" + ext + ")"
+ for fn in fnlist:
+ print "extern " + fn[1] + " " + fn[0] + ";"
+ print "#endif"
+ print
+
+def find(l, x):
+ for i in l:
+ if (i == x):
+ return 1
+ return 0
+
+
+# Write Prototypes
+ext = ""
+fns = []
+fnlist = []
+ifdef = 0
+for i in glext_h:
+ line = re.search('^#ifn?def', i)
+ if (line):
+ ifdef = ifdef + 1
+
+ line = re.search('^#ifndef (GL_.*)', i)
+ if (line):
+ if (not re.search('GL_VERSION.*', line.group(1)) and find(whitelist, line.group(1))):
+ ext = line.group(1)
+
+ line = re.search('^#endif', i)
+ if (line):
+ ifdef = ifdef - 1
+ if (ifdef == 0 and ext != ""):
+ writeproto(ext, fnlist)
+ ext = ""
+ fns = []
+ fnlist = []
+ if (ext != ""):
+ line = re.search('.* (gl.*) \(.*\);', i)
+ if (line):
+ fns += [line.group(1)]
+ line = re.search('.*PFN(.*)PROC.*', i)
+ if (line):
+ for j in fns:
+ if (string.lower(line.group(1)) == string.lower(j)):
+ fnlist += [(j, "PFN" + line.group(1) + "PROC")]
+
+# Write link code
+ext = ""
+fns = []
+fnlist = []
+ifdef = 0
+for i in glext_h:
+ line = re.search('^#ifn?def', i)
+ if (line):
+ ifdef = ifdef + 1
+
+ line = re.search('^#ifndef (GL_.*)', i)
+ if (line):
+ if (not re.search('GL_VERSION.*', line.group(1)) and find(whitelist, line.group(1))):
+ ext = line.group(1)
+
+ line = re.search('^#endif', i)
+ if (line):
+ ifdef = ifdef - 1
+ if (ifdef == 0 and ext != ""):
+ writeext(ext, fnlist)
+ ext = ""
+ fns = []
+ fnlist = []
+ if (ext != ""):
+ line = re.search('.* (gl.*) \(.*\);', i)
+ if (line):
+ fns += [line.group(1)]
+ line = re.search('.*PFN(.*)PROC.*', i)
+ if (line):
+ for j in fns:
+ if (string.lower(line.group(1)) == string.lower(j)):
+ fnlist += [(j, "PFN" + line.group(1) + "PROC")]
+
+# Write header code
+ext = ""
+fns = []
+fnlist = []
+ifdef = 0
+for i in glext_h:
+ line = re.search('^#ifn?def', i)
+ if (line):
+ ifdef = ifdef + 1
+
+ line = re.search('^#ifndef (GL_.*)', i)
+ if (line):
+ if (not re.search('GL_VERSION.*', line.group(1)) and find(whitelist, line.group(1))):
+ ext = line.group(1)
+
+ line = re.search('^#endif', i)
+ if (line):
+ ifdef = ifdef - 1
+ if (ifdef == 0 and ext != ""):
+ writeheader(ext, fnlist)
+ ext = ""
+ fns = []
+ fnlist = []
+ if (ext != ""):
+ line = re.search('.* (gl.*) \(.*\);', i)
+ if (line):
+ fns += [line.group(1)]
+ line = re.search('.*PFN(.*)PROC.*', i)
+ if (line):
+ for j in fns:
+ if (string.lower(line.group(1)) == string.lower(j)):
+ fnlist += [(j, "PFN" + line.group(1) + "PROC")]
+
+# Write Python link code
+ext = ""
+extensions = []
+fns = []
+defines = []
+ifdef = 0
+for i in glext_h:
+ line = re.search('^#ifn?def', i)
+ if (line):
+ ifdef = ifdef + 1
+
+ line = re.search('^#ifndef (GL_.*)', i)
+ if (line):
+ if (not re.search('GL_VERSION.*', line.group(1)) and find(whitelist, line.group(1))):
+ ext = line.group(1)
+
+ line = re.search('^#endif', i)
+ if (line):
+ ifdef = ifdef - 1
+ if (ifdef == 0 and ext != ""):
+ done = 0
+ for e in range(len(extensions)):
+ if extensions[e][0] == ext:
+ extensions[e] = (ext, defines + extensions[e][1], fns + extensions[e][2])
+ done = 1
+ if not done:
+ extensions = extensions + [(ext, defines, fns)]
+ ext = ""
+ fns = []
+ defines = []
+ if (ext != ""):
+ line = re.search('#define +(GL.*) +(0x.*)', i) # #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+ if (line):
+ defines += [(line.group(1), line.group(2))]
+
+ line = re.search('(.* )(gl.*)(\(.*\));', i) # GLAPI void APIENTRY glMultiTexCoord2f (GLenum, GLfloat, GLfloat);
+ if (line):
+ fns += [(line.group(1), line.group(2), line.group(3))]
+
+for ext in extensions:
+ if (find(blacklist, ext[0]) or not find(whitelist, ext[0])):
+ continue
+ print "#if defined(" + ext[0] + ")"
+ for fn in ext[2]:
+ line = re.search('gl(.*)', fn[1])
+ # BGL_Wrap(2, RasterPos2f, void, (GLfloat, GLfloat))
+ rtype = ""
+ for r in string.split(fn[0]):
+ if r != "GLAPI" and r != "APIENTRY":
+ rtype = rtype + " " + r
+ params = ""
+ for p in string.split(fn[2], ','):
+ pline = re.search('(.*) \*', p)
+ if (pline):
+ p = pline.group(1) + "P"
+ if params == "":
+ params = p
+ else:
+ params = params + "," + p
+ if not params[-1] == ")":
+ params = params + ")"
+ print "BGL_Wrap(" + str(len(string.split(fn[2], ','))) + ", " + line.group(1) + ",\t" + rtype + ",\t" + params + ")"
+ print "#endif"
+ print
+
+for ext in extensions:
+ if (find(blacklist, ext[0]) or not find(whitelist, ext[0])):
+ continue
+ print 'PyDict_SetItemString(dict, "' + ext[0] + '", PyInt_FromLong(_' + ext[0] + '))'
+ print "#if defined(" + ext[0] + ")"
+ print "if (bglQueryExtension(_" + ext[0] + ")) {"
+ if len(ext[2]) > 0:
+ for fn in ext[2]:
+ line = re.search('gl(.*)', fn[1])
+ # MethodDef(Vertex3iv),
+ print " BGL_AddMethod(" + line.group(1) + ");"
+ print
+
+ for define in ext[1]:
+ print " BGL_AddConst(" + define[0] + ");"
+ print
+
+ print "}"
+ print "#endif"
+ print
diff --git a/source/gameengine/Rasterizer/RAS_Polygon.cpp b/source/gameengine/Rasterizer/RAS_Polygon.cpp
new file mode 100644
index 00000000000..310c58882c9
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_Polygon.cpp
@@ -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 *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+
+#pragma warning (disable:4786)
+#endif
+
+#include "RAS_Polygon.h"
+
+/*
+RAS_TexVert* RAS_Polygon::GetVertex(int index)
+{
+ if (m_bucket)
+ return m_bucket->GetVertex(m_vertexindexbase.m_vtxarray, m_vertexindexbase.m_indexarray[index]);
+ else
+ return NULL;
+}
+*/
+
+/*void RAS_Polygon::Bucketize(double* oglmatrix)
+{
+ //Transform(trans);
+ if (m_bucket)
+ m_bucket->AddPolygon(this,oglmatrix);
+}
+*/
+
+RAS_Polygon::RAS_Polygon(RAS_MaterialBucket* bucket,
+ bool visible,
+ int numverts,
+ int vtxarrayindex)
+ :m_bucket(bucket),
+ m_vertexindexbase(numverts),
+ m_numverts(numverts),
+ m_edgecode(65535)
+{
+ m_vertexindexbase.m_vtxarray = vtxarrayindex ;//m_bucket->FindVertexArray(numverts);
+ m_polyFlags.Visible = visible;
+}
+
+
+
+int RAS_Polygon::VertexCount()
+{
+ return m_numverts;
+}
+
+
+
+void RAS_Polygon::SetVertex(int i,
+ unsigned int vertexindex ) //const MT_Point3& xyz,const MT_Point2& uv,const unsigned int rgbacolor,const MT_Vector3& normal)
+{
+ m_vertexindexbase.SetIndex(i,vertexindex); //m_bucket->FindOrAddVertex(m_vertexindexbase.m_vtxarray,
+ //xyz,uv,rgbacolor,normal));
+}
+
+
+
+const KX_VertexIndex& RAS_Polygon::GetIndexBase()
+{
+ return m_vertexindexbase;
+}
+
+
+
+void RAS_Polygon::SetVisibleWireframeEdges(int edgecode)
+{
+ m_edgecode = edgecode;
+}
+
+
+
+// each bit is for a visible edge, starting with bit 1 for the first edge, bit 2 for second etc.
+int RAS_Polygon::GetEdgeCode()
+{
+ return m_edgecode;
+}
+
+
+
+bool RAS_Polygon::IsVisible()
+{
+ return m_polyFlags.Visible;
+}
+
+
+
+bool RAS_Polygon::IsCollider()
+{
+ return m_polyFlags.Collider;
+}
+
+
+
+void RAS_Polygon::SetCollider(bool col)
+{
+ m_polyFlags.Collider = col;
+}
+
+
+
+KX_VertexIndex& RAS_Polygon::GetVertexIndexBase()
+{
+ return m_vertexindexbase;
+}
+
+
+
+RAS_MaterialBucket* RAS_Polygon::GetMaterial()
+{
+ return m_bucket;
+}
diff --git a/source/gameengine/Rasterizer/RAS_Polygon.h b/source/gameengine/Rasterizer/RAS_Polygon.h
new file mode 100644
index 00000000000..253faec6e95
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_Polygon.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef __RAS_POLYGON
+#define __RAS_POLYGON
+
+#include "RAS_TexVert.h"
+#include "RAS_MaterialBucket.h"
+
+#include <vector>
+using namespace std;
+
+
+//
+// Bitfield that stores the flags for each CValue derived class
+//
+struct PolygonFlags {
+ PolygonFlags() :
+ Visible(true),
+ Collider(true)
+ {
+ }
+ unsigned char Visible : 1;
+ unsigned char Collider : 1;
+ //int Visible : 1;
+ //int Collider : 1;
+};
+
+class RAS_Polygon
+{
+ RAS_MaterialBucket* m_bucket;
+ KX_VertexIndex m_vertexindexbase;
+ int m_numverts;
+ int m_edgecode;
+ PolygonFlags m_polyFlags;
+
+
+public:
+ RAS_Polygon(RAS_MaterialBucket* bucket,
+ bool visible,
+ int numverts,
+ int vtxarrayindex) ;
+ virtual ~RAS_Polygon() {};
+
+// RAS_TexVert* GetVertex(int index);
+ int VertexCount();
+ void SetVertex(int i, unsigned int vertexindex); //const MT_Point3& xyz,const MT_Point2& uv,const unsigned int rgbacolor,const MT_Vector3& normal)
+
+ const KX_VertexIndex& GetIndexBase();
+
+ void SetVisibleWireframeEdges(int edgecode);
+ // each bit is for a visible edge, starting with bit 1 for the first edge, bit 2 for second etc.
+ int GetEdgeCode();
+
+ bool IsVisible();
+ bool IsCollider();
+ void SetCollider(bool col);
+
+ KX_VertexIndex& GetVertexIndexBase();
+ RAS_MaterialBucket* GetMaterial();
+
+};
+
+#endif
+
diff --git a/source/gameengine/Rasterizer/RAS_Rect.h b/source/gameengine/Rasterizer/RAS_Rect.h
new file mode 100644
index 00000000000..51d8e2cc465
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_Rect.h
@@ -0,0 +1,98 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 _RAS_RECT
+#define _RAS_RECT
+
+/**
+ * @section interface class.
+ * RAS_Rect just encodes a simple rectangle.
+ * Should be part of a generic library
+ */
+
+class RAS_Rect
+{
+public: // todo: make a decent class, and make private
+ int m_x1, m_y1;
+ int m_x2, m_y2;
+
+public:
+ RAS_Rect() : m_x1(0), m_y1(0), m_x2(0), m_y2(0) {}
+ int GetWidth(
+ ) const {
+ return m_x2 - m_x1;
+ }
+ int GetHeight(
+ ) const {
+ return m_y2 - m_y1;
+ }
+ int GetLeft(
+ ) const {
+ return m_x1;
+ }
+ int GetRight(
+ ) const {
+ return m_x2;
+ }
+ int GetBottom(
+ ) const {
+ return m_y1;
+ }
+ int GetTop(
+ ) const {
+ return m_y2;
+ }
+
+ void SetLeft(
+ int x1)
+ {
+ m_x1 = x1;
+ }
+ void SetBottom(
+ int y1)
+ {
+ m_y1 = y1;
+ }
+ void SetRight(
+ int x2)
+ {
+ m_x2 = x2;
+ }
+ void SetTop(
+ int y2)
+ {
+ m_y2 = y2;
+ }
+};
+
+#endif // _RAS_RECT
+
diff --git a/source/gameengine/Rasterizer/RAS_TexMatrix.h b/source/gameengine/Rasterizer/RAS_TexMatrix.h
new file mode 100644
index 00000000000..2aceca4e1ce
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_TexMatrix.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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef __RASTEXMATRIX
+#define __RASTEXMATRIX
+
+#include "MT_Matrix3x3.h"
+#include "MT_Point3.h"
+#include "MT_Point2.h"
+#include "RAS_TexVert.h"
+
+void RAS_CalcTexMatrix(RAS_TexVert p[3],MT_Point3& origin,MT_Vector3& udir,MT_Vector3& vdir);
+
+#endif //__RASTEXMATRIX
+
diff --git a/source/gameengine/Rasterizer/RAS_TexVert.cpp b/source/gameengine/Rasterizer/RAS_TexVert.cpp
new file mode 100644
index 00000000000..79e6cbdb7db
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_TexVert.cpp
@@ -0,0 +1,180 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "RAS_TexVert.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define SHORT(x) short(x*32767.0)
+
+RAS_TexVert::RAS_TexVert(const MT_Point3& xyz,
+ const MT_Point2& uv,
+ const MT_Point2& uv2,
+ const MT_Vector4& tangent,
+ const unsigned int rgba,
+ const MT_Vector3& normal,
+ const short flag)
+{
+ xyz.getValue(m_localxyz);
+ uv.getValue(m_uv1);
+ uv2.getValue(m_uv2);
+ SetRGBA(rgba);
+ SetNormal(normal);
+ tangent.getValue(m_tangent);
+ m_flag = flag;
+ m_unit = 2;
+}
+
+const MT_Point3& RAS_TexVert::xyz()
+{
+ g_pt3.setValue(m_localxyz);
+ return g_pt3;
+}
+
+void RAS_TexVert::SetRGBA(const MT_Vector4& rgba)
+{
+ unsigned char *colp = (unsigned char*) &m_rgba;
+ colp[0] = (unsigned char) (rgba[0]*255.0);
+ colp[1] = (unsigned char) (rgba[1]*255.0);
+ colp[2] = (unsigned char) (rgba[2]*255.0);
+ colp[3] = (unsigned char) (rgba[3]*255.0);
+}
+
+
+void RAS_TexVert::SetXYZ(const MT_Point3& xyz)
+{
+ xyz.getValue(m_localxyz);
+}
+
+
+
+void RAS_TexVert::SetUV(const MT_Point2& uv)
+{
+ uv.getValue(m_uv1);
+}
+
+void RAS_TexVert::SetUV2(const MT_Point2& uv)
+{
+ uv.getValue(m_uv2);
+}
+
+
+void RAS_TexVert::SetRGBA(const unsigned int rgba)
+{
+ m_rgba = rgba;
+}
+
+
+void RAS_TexVert::SetFlag(const short flag)
+{
+ m_flag = flag;
+}
+
+void RAS_TexVert::SetUnit(const unsigned int u)
+{
+ m_unit = u<=TV_MAX?u:TV_MAX;
+}
+
+void RAS_TexVert::SetNormal(const MT_Vector3& normal)
+{
+ normal.getValue(m_normal);
+}
+
+#ifndef RAS_TexVert_INLINE
+
+// leave multiline for debugging
+const float* RAS_TexVert::getUV1 () const
+{
+ return m_uv1;
+}
+
+const float* RAS_TexVert::getUV2 () const
+{
+ return m_uv2;
+}
+
+
+
+const float* RAS_TexVert::getNormal() const
+{
+ return m_normal;
+}
+
+const float* RAS_TexVert::getTangent() const
+{
+ return m_tangent;
+}
+
+
+const float* RAS_TexVert::getLocalXYZ() const
+{
+ return m_localxyz;
+}
+
+const unsigned char* RAS_TexVert::getRGBA() const
+{
+ return (unsigned char*) &m_rgba;
+}
+
+#endif
+
+// compare two vertices, and return TRUE if both are almost identical (they can be shared)
+bool RAS_TexVert::closeTo(const RAS_TexVert* other)
+{
+ return (m_flag == other->m_flag &&
+ m_rgba == other->m_rgba &&
+ MT_fuzzyEqual(MT_Vector3(m_normal), MT_Vector3(other->m_normal)) &&
+ MT_fuzzyEqual(MT_Vector2(m_uv1), MT_Vector2(other->m_uv1)) &&
+ MT_fuzzyEqual(MT_Vector2(m_uv2), MT_Vector2(other->m_uv2)) && // p --
+ MT_fuzzyEqual(MT_Vector3(m_localxyz), MT_Vector3(other->m_localxyz))) ;
+}
+
+short RAS_TexVert::getFlag() const
+{
+ return m_flag;
+}
+
+
+unsigned int RAS_TexVert::getUnit() const
+{
+ return m_unit;
+}
+
+
+void RAS_TexVert::getOffsets(void* &xyz, void* &uv1, void* &rgba, void* &normal) const
+{
+ xyz = (void *) m_localxyz;
+ uv1 = (void *) m_uv1;
+ rgba = (void *) &m_rgba;
+ normal = (void *) m_normal;
+}
diff --git a/source/gameengine/Rasterizer/RAS_TexVert.h b/source/gameengine/Rasterizer/RAS_TexVert.h
new file mode 100644
index 00000000000..b177f096dbc
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_TexVert.h
@@ -0,0 +1,135 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __RAS_TEXVERT
+#define __RAS_TEXVERT
+
+
+#include "MT_Point3.h"
+#include "MT_Point2.h"
+#include "MT_Transform.h"
+
+static MT_Point3 g_pt3;
+static MT_Point2 g_pt2;
+
+#define TV_CALCFACENORMAL 0x0001
+#define TV_2NDUV 0x0002
+
+#define TV_MAX 3//match Def in BL_Material.h
+
+#define RAS_TexVert_INLINE 1
+
+class RAS_TexVert
+{
+
+ float m_localxyz[3]; // 3*4 = 12
+ float m_uv1[2]; // 2*4 = 8
+ float m_uv2[2]; // 2*4 = 8
+ unsigned int m_rgba; // 4
+ float m_tangent[4]; // 4*2 = 8
+ float m_normal[3]; // 3*2 = 6
+ short m_flag; // 2
+ unsigned int m_unit; // 4
+ //---------
+ // 52
+ //32 bytes total size, fits nice = 52 = not fit nice.
+ // We'll go for 64 bytes total size - 24 bytes left.
+public:
+ short getFlag() const;
+ unsigned int getUnit() const;
+
+ RAS_TexVert()// :m_xyz(0,0,0),m_uv(0,0),m_rgba(0)
+ {}
+ RAS_TexVert(const MT_Point3& xyz,
+ const MT_Point2& uv,
+ const MT_Point2& uv2,
+ const MT_Vector4& tangent,
+ const unsigned int rgba,
+ const MT_Vector3& normal,
+ const short flag);
+ ~RAS_TexVert() {};
+
+ // leave multiline for debugging
+#ifdef RAS_TexVert_INLINE
+ const float* getUV1 () const {
+ return m_uv1;
+ };
+
+ const float* getUV2 () const {
+ return m_uv2;
+ };
+
+ const float* getLocalXYZ() const {
+ return m_localxyz;
+ };
+
+ const float* getNormal() const {
+ return m_normal;
+ }
+
+ const float* getTangent() const {
+ return m_tangent;
+ }
+
+ const unsigned char* getRGBA() const {
+ return (unsigned char *) &m_rgba;
+ }
+#else
+ const float* getUV1 () const;
+ const float* getUV2 () const;
+ const float* getNormal() const;
+ const float* getLocalXYZ() const;
+ const unsigned char* getRGBA() const;
+#endif
+ void SetXYZ(const MT_Point3& xyz);
+ void SetUV(const MT_Point2& uv);
+ void SetUV2(const MT_Point2& uv);
+
+ void SetRGBA(const unsigned int rgba);
+ void SetNormal(const MT_Vector3& normal);
+ void SetFlag(const short flag);
+ void SetUnit(const unsigned u);
+
+ void SetRGBA(const MT_Vector4& rgba);
+ const MT_Point3& xyz();
+
+ // compare two vertices, and return TRUE if both are almost identical (they can be shared)
+ bool closeTo(const RAS_TexVert* other);
+
+ bool closeTo(const MT_Point3& otherxyz,
+ const MT_Point2& otheruv,
+ const unsigned int otherrgba,
+ short othernormal[3]) const;
+ void getOffsets(void*&xyz, void *&uv1, void *&rgba, void *&normal) const;
+};
+
+#endif //__RAS_TEXVERT
+
diff --git a/source/gameengine/Rasterizer/RAS_texmatrix.cpp b/source/gameengine/Rasterizer/RAS_texmatrix.cpp
new file mode 100644
index 00000000000..791d6e3dc7d
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_texmatrix.cpp
@@ -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 *****
+ */
+
+#include "RAS_TexMatrix.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void RAS_CalcTexMatrix(RAS_TexVert p[3],MT_Point3& origin,MT_Vector3& udir,MT_Vector3& vdir)
+{
+// precondition: 3 vertices are non-colinear
+
+ MT_Vector3 vec1 = p[1].xyz()-p[0].xyz();
+ MT_Vector3 vec2 = p[2].xyz()-p[0].xyz();
+ MT_Vector3 normal = vec1.cross(vec2);
+ normal.normalize();
+
+ // determine which coordinate we drop, ie. max coordinate in the normal
+
+
+ int ZCOORD = normal.closestAxis();
+ int XCOORD = (ZCOORD+1)%3;
+ int YCOORD = (ZCOORD+2)%3;
+
+ // ax+by+cz+d=0
+ MT_Scalar d = -p[0].xyz().dot(normal);
+
+
+ MT_Matrix3x3 mat3( p[0].getUV1()[0],p[0].getUV1()[1], 1,
+ p[1].getUV1()[0],p[1].getUV1()[1], 1,
+ p[2].getUV1()[0],p[2].getUV1()[1], 1);
+
+
+ MT_Matrix3x3 mat3inv = mat3.inverse();
+
+ MT_Vector3 p123x(p[0].xyz()[XCOORD],p[1].xyz()[XCOORD],p[2].xyz()[XCOORD]);
+ MT_Vector3 resultx = mat3inv*p123x;
+ MT_Vector3 p123y(p[0].xyz()[YCOORD],p[1].xyz()[YCOORD],p[2].xyz()[YCOORD]);
+ MT_Vector3 resulty = mat3inv*p123y;
+
+ // normal[ZCOORD] is not zero, because it's chosen to be maximal (absolute), and normal has length 1,
+ // so at least on of the coords is <> 0
+
+ //droppedvalue udir.dot(normal) =0
+ MT_Scalar droppedu = -(resultx.x()*normal[XCOORD]+resulty.x()*normal[YCOORD])/normal[ZCOORD];
+ udir[XCOORD] = resultx.x();
+ udir[YCOORD] = resulty.x();
+ udir[ZCOORD] = droppedu;
+ MT_Scalar droppedv = -(resultx.y()*normal[XCOORD]+resulty.y()*normal[YCOORD])/normal[ZCOORD];
+ vdir[XCOORD] = resultx.y();
+ vdir[YCOORD] = resulty.y();
+ vdir[ZCOORD] = droppedv;
+ // droppedvalue b = -(ax+cz+d)/y;
+ MT_Scalar droppedvalue = -((resultx.z()*normal[XCOORD] + resulty.z()*normal[YCOORD]+d))/normal[ZCOORD];
+ origin[XCOORD] = resultx.z();
+ origin[YCOORD] = resulty.z();
+ origin[ZCOORD] = droppedvalue;
+
+
+}
+
+#ifdef _TEXOWNMAIN
+
+int main()
+{
+
+ MT_Point2 puv0={0,0};
+ MT_Point3 pxyz0 (0,0,128);
+
+ MT_Scalar puv1[2]={1,0};
+ MT_Point3 pxyz1(128,0,128);
+
+ MT_Scalar puv2[2]={1,1};
+ MT_Point3 pxyz2(128,0,0);
+
+ RAS_TexVert p0(pxyz0,puv0);
+ RAS_TexVert p1(pxyz1,puv1);
+ RAS_TexVert p2(pxyz2,puv2);
+
+ RAS_TexVert vertices[3] =
+ {
+ p0,
+ p1,
+ p2
+ };
+
+ MT_Vector3 udir,vdir;
+ MT_Point3 origin;
+ CalcTexMatrix(vertices,origin,udir,vdir);
+
+ MT_Point3 testpoint(128,32,64);
+
+ MT_Scalar lenu = udir.length2();
+ MT_Scalar lenv = vdir.length2();
+
+ MT_Scalar testu=((pxyz2-origin).dot(udir))/lenu;
+ MT_Scalar testv=((pxyz2-origin).dot(vdir))/lenv;
+
+
+
+
+ return 0;
+}
+
+#endif // _TEXOWNMAIN
diff --git a/source/gameengine/Rasterizer/SConscript b/source/gameengine/Rasterizer/SConscript
new file mode 100644
index 00000000000..2097540ed7e
--- /dev/null
+++ b/source/gameengine/Rasterizer/SConscript
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('*.cpp')
+
+incs = '. #source/kernel/gen_system #intern/string #intern/moto/include'
+
+if env['OURPLATFORM']=='win32-vc':
+ cflags = []
+ cflags.append('/Ox')
+ env.BlenderLib ( 'bf_rasterizer', sources, Split(incs), [], libtype=['game','player'], priority=[35,115], compileflags = cflags )
+else:
+ env.BlenderLib ( 'bf_rasterizer', sources, Split(incs), [], libtype=['game','player'], priority=[35,115] )
diff --git a/source/gameengine/SConscript b/source/gameengine/SConscript
new file mode 100644
index 00000000000..c2750d19706
--- /dev/null
+++ b/source/gameengine/SConscript
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+Import ('env')
+
+SConscript(['BlenderRoutines/SConscript',
+ 'Converter/SConscript',
+ 'Expressions/SConscript',
+ 'GameLogic/SConscript',
+ 'Ketsji/SConscript',
+ 'Ketsji/KXNetwork/SConscript',
+ 'Network/SConscript',
+ 'Network/LoopBackNetwork/SConscript',
+ 'Physics/common/SConscript',
+ 'Physics/Dummy/SConscript',
+ 'Rasterizer/SConscript',
+ 'Rasterizer/RAS_OpenGLRasterizer/SConscript',
+ 'SceneGraph/SConscript',
+ 'Physics/Bullet/SConscript',
+ 'Physics/Sumo/SConscript'
+ ])
+
+if env['WITH_BF_PLAYER']:
+ SConscript(['GamePlayer/SConscript'])
+
+#if user_options_dict['USE_PHYSICS'] == 'solid':
+# SConscript(['Physics/Sumo/SConscript'])
+#elif user_options_dict['USE_PHYSICS'] == 'ode':
+# SConscript(['Physics/BlOde/SConscript'])
diff --git a/source/gameengine/SceneGraph/CMakeLists.txt b/source/gameengine/SceneGraph/CMakeLists.txt
new file mode 100644
index 00000000000..1cc9d7b7acf
--- /dev/null
+++ b/source/gameengine/SceneGraph/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 *.cpp)
+
+SET(INC
+ .
+ ../../../intern/moto/include
+)
+
+BLENDERLIB(bf_scenegraph "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_scenegraph', sources, Split(incs), [], libtype=['game','player'], priority=[50,130] )
diff --git a/source/gameengine/SceneGraph/Makefile b/source/gameengine/SceneGraph/Makefile
new file mode 100644
index 00000000000..bc184c8faba
--- /dev/null
+++ b/source/gameengine/SceneGraph/Makefile
@@ -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 *****
+#
+#
+
+LIBNAME = scenegraph
+DIR = $(OCGDIR)/gameengine/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I$(NAN_MOTO)/include
diff --git a/source/gameengine/SceneGraph/SConscript b/source/gameengine/SceneGraph/SConscript
new file mode 100644
index 00000000000..23c1c24c297
--- /dev/null
+++ b/source/gameengine/SceneGraph/SConscript
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+
+Import ('env')
+
+sources = env.Glob('*.cpp') #'SG_BBox.cpp SG_Controller.cpp SG_IObject.cpp SG_Node.cpp SG_Spatial.cpp SG_Tree.cpp'
+
+incs = '. #intern/moto/include'
+
+env.BlenderLib ( 'bf_scenegraph', sources, Split(incs), [], libtype=['game','player'], priority=[50,130] )
diff --git a/source/gameengine/SceneGraph/SG_BBox.cpp b/source/gameengine/SceneGraph/SG_BBox.cpp
new file mode 100644
index 00000000000..6f06e9b0424
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_BBox.cpp
@@ -0,0 +1,253 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Bounding Box
+ */
+
+#include <math.h>
+
+ #include "SG_BBox.h"
+ #include "SG_Node.h"
+
+SG_BBox::SG_BBox() :
+ m_min(MT_Point3(0., 0., 0.)),
+ m_max(MT_Point3(0., 0., 0.))
+{
+}
+
+SG_BBox::SG_BBox(const MT_Point3 &min, const MT_Point3 &max) :
+ m_min(min),
+ m_max(max)
+{
+}
+
+SG_BBox::SG_BBox(const SG_BBox &other, const MT_Transform &world) :
+ m_min(world(other.m_min)),
+ m_max(world(other.m_max))
+{
+ *this += world(MT_Point3(m_min[0], m_min[1], m_max[2]));
+ *this += world(MT_Point3(m_min[0], m_max[1], m_min[2]));
+ *this += world(MT_Point3(m_min[0], m_max[1], m_max[2]));
+ *this += world(MT_Point3(m_max[0], m_min[1], m_min[2]));
+ *this += world(MT_Point3(m_max[0], m_min[1], m_max[2]));
+ *this += world(MT_Point3(m_max[0], m_max[1], m_min[2]));
+}
+
+SG_BBox::SG_BBox(const SG_BBox &other) :
+ m_min(other.m_min),
+ m_max(other.m_max)
+{
+}
+
+SG_BBox::~ SG_BBox()
+{
+}
+
+SG_BBox& SG_BBox::operator +=(const MT_Point3 &point)
+{
+ if (point[0] < m_min[0])
+ m_min[0] = point[0];
+ else if (point[0] > m_max[0])
+ m_max[0] = point[0];
+
+ if (point[1] < m_min[1])
+ m_min[1] = point[1];
+ else if (point[1] > m_max[1])
+ m_max[1] = point[1];
+
+ if (point[2] < m_min[2])
+ m_min[2] = point[2];
+ else if (point[2] > m_max[2])
+ m_max[2] = point[2];
+
+ return *this;
+}
+
+SG_BBox& SG_BBox::operator += (const SG_BBox &bbox)
+{
+ *this += bbox.m_min;
+ *this += bbox.m_max;
+
+ return *this;
+}
+
+SG_BBox SG_BBox::operator +(const SG_BBox &bbox2) const
+{
+ SG_BBox ret = *this;
+ ret += bbox2;
+ return ret;
+}
+
+MT_Scalar SG_BBox::volume() const
+{
+ MT_Vector3 size = m_max - m_min;
+ return size[0]*size[1]*size[2];
+}
+#if 0
+void SG_BBox::translate(const MT_Vector3& dx)
+{
+ m_min += dx;
+ m_max += dx;
+}
+
+void SG_BBox::scale(const MT_Vector3& size, const MT_Point3& point)
+{
+ MT_Vector3 center = (m_max - m_min)/2. + point;
+ m_max = (m_max - center)*size;
+ m_min = (m_min - center)*size;
+}
+#endif
+
+SG_BBox SG_BBox::transform(const MT_Transform &world) const
+{
+ SG_BBox bbox(world(m_min), world(m_max));
+ bbox += world(MT_Point3(m_min[0], m_min[1], m_max[2]));
+ bbox += world(MT_Point3(m_min[0], m_max[1], m_min[2]));
+ bbox += world(MT_Point3(m_min[0], m_max[1], m_max[2]));
+ bbox += world(MT_Point3(m_max[0], m_min[1], m_min[2]));
+ bbox += world(MT_Point3(m_max[0], m_min[1], m_max[2]));
+ bbox += world(MT_Point3(m_max[0], m_max[1], m_min[2]));
+ return bbox;
+}
+
+bool SG_BBox::inside(const MT_Point3 &point) const
+{
+ return point[0] >= m_min[0] && point[0] <= m_max[0] &&
+ point[1] >= m_min[1] && point[1] <= m_max[1] &&
+ point[2] >= m_min[2] && point[2] <= m_max[2];
+}
+
+bool SG_BBox::inside(const SG_BBox& other) const
+{
+ return inside(other.m_min) && inside(other.m_max);
+}
+
+bool SG_BBox::intersects(const SG_BBox& other) const
+{
+ return inside(other.m_min) != inside(other.m_max);
+}
+
+bool SG_BBox::outside(const SG_BBox& other) const
+{
+ return !inside(other.m_min) && !inside(other.m_max);
+}
+
+SG_BBox::intersect SG_BBox::test(const SG_BBox& other) const
+{
+ bool point1(inside(other.m_min)), point2(inside(other.m_max));
+
+ return point1?(point2?INSIDE:INTERSECT):(point2?INTERSECT:OUTSIDE);
+}
+
+void SG_BBox::get(MT_Point3 *box, const MT_Transform &world) const
+{
+ *box++ = world(m_min);
+ *box++ = world(MT_Point3(m_min[0], m_min[1], m_max[2]));
+ *box++ = world(MT_Point3(m_min[0], m_max[1], m_min[2]));
+ *box++ = world(MT_Point3(m_min[0], m_max[1], m_max[2]));
+ *box++ = world(MT_Point3(m_max[0], m_min[1], m_min[2]));
+ *box++ = world(MT_Point3(m_max[0], m_min[1], m_max[2]));
+ *box++ = world(MT_Point3(m_max[0], m_max[1], m_min[2]));
+ *box++ = world(m_max);
+}
+
+void SG_BBox::getaa(MT_Point3 *box, const MT_Transform &world) const
+{
+ const MT_Point3 min(world(m_min)), max(world(m_max));
+ *box++ = min;
+ *box++ = MT_Point3(min[0], min[1], max[2]);
+ *box++ = MT_Point3(min[0], max[1], min[2]);
+ *box++ = MT_Point3(min[0], max[1], max[2]);
+ *box++ = MT_Point3(max[0], min[1], min[2]);
+ *box++ = MT_Point3(max[0], min[1], max[2]);
+ *box++ = MT_Point3(max[0], max[1], min[2]);
+ *box++ = max;
+}
+
+void SG_BBox::split(SG_BBox &left, SG_BBox &right) const
+{
+ MT_Scalar sizex = m_max[0] - m_min[0];
+ MT_Scalar sizey = m_max[1] - m_min[1];
+ MT_Scalar sizez = m_max[2] - m_min[2];
+ if (sizex < sizey)
+ {
+ if (sizey > sizez)
+ {
+ left.m_min = m_min;
+ left.m_max[0] = m_max[0];
+ left.m_max[1] = m_min[1] + sizey/2.0;
+ left.m_max[2] = m_max[2];
+
+ right.m_min[0] = m_min[0];
+ right.m_min[1] = m_min[1] + sizey/2.0;
+ right.m_min[2] = m_min[2];
+ right.m_max = m_max;
+ std::cout << "splity" << std::endl;
+ } else {
+ left.m_min = m_min;
+ left.m_max[0] = m_max[0];
+ left.m_max[1] = m_max[1];
+ left.m_max[2] = m_min[2] + sizez/2.0;
+
+ right.m_min[0] = m_min[0];
+ right.m_min[1] = m_min[1];
+ right.m_min[2] = m_min[2] + sizez/2.0;
+ right.m_max = m_max;
+ std::cout << "splitz" << std::endl;
+ }
+ } else {
+ if (sizex > sizez)
+ {
+ left.m_min = m_min;
+ left.m_max[0] = m_min[0] + sizex/2.0;
+ left.m_max[1] = m_max[1];
+ left.m_max[2] = m_max[2];
+
+ right.m_min[0] = m_min[0] + sizex/2.0;
+ right.m_min[1] = m_min[1];
+ right.m_min[2] = m_min[2];
+ right.m_max = m_max;
+ std::cout << "splitx" << std::endl;
+ } else {
+ left.m_min = m_min;
+ left.m_max[0] = m_max[0];
+ left.m_max[1] = m_max[1];
+ left.m_max[2] = m_min[2] + sizez/2.0;
+
+ right.m_min[0] = m_min[0];
+ right.m_min[1] = m_min[1];
+ right.m_min[2] = m_min[2] + sizez/2.0;
+ right.m_max = m_max;
+ std::cout << "splitz" << std::endl;
+ }
+ }
+
+ //std::cout << "Left: " << left.m_min << " -> " << left.m_max << " Right: " << right.m_min << " -> " << right.m_max << std::endl;
+}
diff --git a/source/gameengine/SceneGraph/SG_BBox.h b/source/gameengine/SceneGraph/SG_BBox.h
new file mode 100644
index 00000000000..5a4d396faf1
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_BBox.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 *****
+ * Bounding Box
+ */
+
+#ifndef __SG_BBOX_H__
+#define __SG_BBOX_H__
+
+#include "MT_Scalar.h"
+#include "MT_Point3.h"
+#include "MT_Vector3.h"
+#include "MT_Transform.h"
+
+#include <vector>
+
+class SG_Node;
+
+/**
+ * Bounding box class.
+ * Holds the minimum and maximum axis aligned points of a node's bounding box,
+ * in world coordinates.
+ */
+class SG_BBox
+{
+ MT_Point3 m_min;
+ MT_Point3 m_max;
+public:
+ typedef enum { INSIDE, INTERSECT, OUTSIDE } intersect;
+ SG_BBox();
+ SG_BBox(const MT_Point3 &min, const MT_Point3 &max);
+ SG_BBox(const SG_BBox &other, const MT_Transform &world);
+ SG_BBox(const SG_BBox &other);
+ ~SG_BBox();
+
+ /**
+ * Enlarges the bounding box to contain the specified point.
+ */
+ SG_BBox& operator +=(const MT_Point3 &point);
+ /**
+ * Enlarges the bounding box to contain the specified bound box.
+ */
+ SG_BBox& operator +=(const SG_BBox &bbox);
+
+ SG_BBox operator + (const SG_BBox &bbox2) const;
+#if 0
+ /**
+ * Translates the bounding box.
+ */
+ void translate(const MT_Vector3 &dx);
+ /**
+ * Scales the bounding box about the optional point.
+ */
+ void scale(const MT_Vector3 &size, const MT_Point3 &point = MT_Point3(0., 0., 0.));
+#endif
+ SG_BBox transform(const MT_Transform &world) const;
+ /**
+ * Computes the volume of the bounding box.
+ */
+ MT_Scalar volume() const;
+
+ /**
+ * Test if the given point is inside this bounding box.
+ */
+ bool inside(const MT_Point3 &point) const;
+
+ /**
+ * Test if the given bounding box is inside this bounding box.
+ */
+ bool inside(const SG_BBox &other) const;
+
+ /**
+ * Test if the given bounding box is outside this bounding box.
+ */
+ bool outside(const SG_BBox &other) const;
+
+ /**
+ * Test if the given bounding box intersects this bounding box.
+ */
+ bool intersects(const SG_BBox &other) const;
+
+ /**
+ * Test the given bounding box with this bounding box.
+ */
+ intersect test(const SG_BBox &other) const;
+
+ /**
+ * Get the eight points that define this bounding box.
+ *
+ * @param world a world transform to apply to the produced points bounding box.
+ */
+ void get(MT_Point3 *box, const MT_Transform &world) const;
+ /**
+ * Get the eight points that define this axis aligned bounding box.
+ * This differs from SG_BBox::get() in that the produced box will be world axis aligned.
+ * The maximum & minimum local points will be transformed *before* splitting to 8 points.
+ * @param world a world transform to be applied.
+ */
+ void getaa(MT_Point3 *box, const MT_Transform &world) const;
+
+ void split(SG_BBox &left, SG_BBox &right) const;
+
+ friend class SG_Tree;
+
+};
+
+#endif /* __SG_BBOX_H__ */
diff --git a/source/gameengine/SceneGraph/SG_Controller.cpp b/source/gameengine/SceneGraph/SG_Controller.cpp
new file mode 100644
index 00000000000..86dbc7c2c42
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_Controller.cpp
@@ -0,0 +1,53 @@
+/**
+ * @file SG_Controller.cpp
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SG_Controller.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+ void
+SG_Controller::
+SetObject(SG_IObject* obj)
+{
+ m_pObject = obj; // no checks yet ?
+}
+
+ void
+SG_Controller::
+ClearObject(
+){
+ m_pObject = NULL;
+}
+
+
diff --git a/source/gameengine/SceneGraph/SG_Controller.h b/source/gameengine/SceneGraph/SG_Controller.h
new file mode 100644
index 00000000000..b5bb6943479
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_Controller.h
@@ -0,0 +1,120 @@
+/**
+ * Implementationclass to derive controllers from
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __SG_CONTROLLER_H
+#define __SG_CONTROLLER_H
+
+#include "SG_IObject.h"
+
+/**
+ * A scenegraph controller
+ */
+class SG_Controller
+{
+public:
+ SG_Controller(
+ ) :
+ m_pObject(NULL) {
+ }
+
+ virtual
+ ~SG_Controller(
+ ) {};
+
+ virtual
+ bool
+ Update(
+ double time
+ )=0;
+
+ virtual
+ void
+ SetObject (
+ SG_IObject* object
+ );
+
+ void
+ ClearObject(
+ );
+
+ virtual
+ void
+ SetSimulatedTime(
+ double time
+ )=0;
+
+ virtual
+ SG_Controller*
+ GetReplica(
+ class SG_Node* destnode
+ )=0;
+
+ /**
+ * Hacky way of passing options to specific controllers
+ * @param option An integer identifying the option.
+ * @param value The value of this option.
+ * @attention This has been placed here to give sca-elements
+ * @attention some control over the controllers. This is
+ * @attention necessary because the identity of the controller
+ * @attention is lost on the way here.
+ */
+ virtual
+ void
+ SetOption(
+ int option,
+ int value
+ )=0;
+
+ /**
+ * Option-identifiers: SG_CONTR_<controller-type>_<option>.
+ * Options only apply to a specific controller type. The
+ * semantics are defined by whoever uses the setting.
+ */
+ enum SG_Controller_option {
+ SG_CONTR_NODEF = 0,
+ SG_CONTR_IPO_IPO_AS_FORCE,
+ SG_CONTR_IPO_FORCES_ACT_LOCAL,
+ SG_CONTR_CAMIPO_LENS,
+ SG_CONTR_CAMIPO_CLIPEND,
+ SG_CONTR_CAMIPO_CLIPSTART,
+ SG_CONTR_MAX
+ };
+
+protected:
+ SG_IObject* m_pObject;
+
+};
+
+#endif //__SG_CONTROLLER_H
+
diff --git a/source/gameengine/SceneGraph/SG_IObject.cpp b/source/gameengine/SceneGraph/SG_IObject.cpp
new file mode 100644
index 00000000000..232ceb06958
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_IObject.cpp
@@ -0,0 +1,167 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SG_IObject.h"
+#include "SG_Controller.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+SG_IObject::
+SG_IObject(
+ void* clientobj,
+ void* clientinfo,
+ SG_Callbacks callbacks
+):
+ m_SGclientObject(clientobj),
+ m_SGclientInfo(clientinfo),
+ m_callbacks(callbacks)
+{
+ //nothing to do
+}
+
+SG_IObject::
+SG_IObject(
+ const SG_IObject &other
+) :
+ m_SGclientObject(other.m_SGclientObject),
+ m_SGclientInfo(other.m_SGclientInfo),
+ m_callbacks(other.m_callbacks)
+{
+ //nothing to do
+}
+
+ void
+SG_IObject::
+AddSGController(
+ SG_Controller* cont
+){
+ m_SGcontrollers.push_back(cont);
+}
+
+ void
+SG_IObject::
+RemoveAllControllers(
+) {
+ m_SGcontrollers.clear();
+}
+
+/// Needed for replication
+ SGControllerList&
+SG_IObject::
+GetSGControllerList(
+){
+ return m_SGcontrollers;
+}
+
+ void*
+SG_IObject::
+GetSGClientObject(
+){
+ return m_SGclientObject;
+}
+
+const
+ void*
+SG_IObject::
+GetSGClientObject(
+) const {
+ return m_SGclientObject;
+}
+
+ void
+SG_IObject::
+SetSGClientObject(
+ void* clientObject
+){
+ m_SGclientObject = clientObject;
+}
+
+
+ void
+SG_IObject::
+ActivateReplicationCallback(
+ SG_IObject *replica
+){
+ if (m_callbacks.m_replicafunc)
+ {
+ // Call client provided replication func
+ m_callbacks.m_replicafunc(replica,m_SGclientObject,m_SGclientInfo);
+ }
+};
+
+ void
+SG_IObject::
+ActivateDestructionCallback(
+){
+ if (m_callbacks.m_destructionfunc)
+ {
+ // Call client provided destruction function on this!
+ m_callbacks.m_destructionfunc(this,m_SGclientObject,m_SGclientInfo);
+ }
+}
+
+ void
+SG_IObject::
+ActivateUpdateTransformCallback(
+){
+ if (m_callbacks.m_updatefunc)
+ {
+ // Call client provided update func.
+ m_callbacks.m_updatefunc(this, m_SGclientObject, m_SGclientInfo);
+ }
+}
+
+ void
+SG_IObject::
+SetControllerTime(
+ double time
+){
+ SGControllerList::iterator contit;
+
+ for (contit = m_SGcontrollers.begin();contit!=m_SGcontrollers.end();++contit)
+ {
+ (*contit)->SetSimulatedTime(time);
+ }
+}
+
+
+SG_IObject::
+~SG_IObject()
+{
+ SGControllerList::iterator contit;
+
+ for (contit = m_SGcontrollers.begin();contit!=m_SGcontrollers.end();++contit)
+ {
+ delete (*contit);
+ }
+}
diff --git a/source/gameengine/SceneGraph/SG_IObject.h b/source/gameengine/SceneGraph/SG_IObject.h
new file mode 100644
index 00000000000..b0c1d64cf69
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_IObject.h
@@ -0,0 +1,235 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __SG_IOBJECT
+#define __SG_IOBJECT
+
+#include <vector>
+
+class SG_Controller;
+class SG_IObject;
+
+typedef std::vector<SG_Controller*> SGControllerList;
+
+typedef void* (*SG_ReplicationNewCallback)(
+ SG_IObject* sgobject,
+ void* clientobj,
+ void* clientinfo
+);
+
+typedef void* (*SG_DestructionNewCallback)(
+ SG_IObject* sgobject,
+ void* clientobj,
+ void* clientinfo
+);
+
+typedef void (*SG_UpdateTransformCallback)(
+ SG_IObject* sgobject,
+ void* clientobj,
+ void* clientinfo
+);
+
+
+/**
+ * SG_Callbacks hold 2 call backs to the outside world.
+ * The first is meant to be called when objects are replicated.
+ * And allows the outside world to syncronise external objects
+ * with replicated nodes and their children.
+ * The second is called when a node is detroyed and again
+ * is their for synconisation purposes
+ * These callbacks may both be NULL.
+ * The efficacy of this approach has not been proved some
+ * alternatives might be to perform all replication and destruction
+ * externally.
+ * To define a class interface rather than a simple function
+ * call back so that replication information can be transmitted from
+ * parent->child.
+ */
+struct SG_Callbacks
+{
+ SG_Callbacks(
+ ):
+ m_replicafunc(NULL),
+ m_destructionfunc(NULL),
+ m_updatefunc(NULL)
+ {
+ };
+
+ SG_Callbacks(
+ SG_ReplicationNewCallback repfunc,
+ SG_DestructionNewCallback destructfunc,
+ SG_UpdateTransformCallback updatefunc
+ ):
+ m_replicafunc(repfunc),
+ m_destructionfunc(destructfunc),
+ m_updatefunc(updatefunc)
+ {
+ };
+
+ SG_ReplicationNewCallback m_replicafunc;
+ SG_DestructionNewCallback m_destructionfunc;
+ SG_UpdateTransformCallback m_updatefunc;
+};
+
+/**
+base object that can be part of the scenegraph.
+*/
+class SG_IObject
+{
+private :
+
+ void* m_SGclientObject;
+ void* m_SGclientInfo;
+ SG_Callbacks m_callbacks;
+ SGControllerList m_SGcontrollers;
+
+public:
+
+
+ virtual ~SG_IObject();
+
+
+ /**
+ * Add a pointer to a controller allocated on the heap, to
+ * this node. This memory for this controller becomes the
+ * responsibility of this class. It will be deleted when
+ * this object is deleted.
+ */
+
+ void
+ AddSGController(
+ SG_Controller* cont
+ );
+
+ /**
+ * Clear the array of pointers to controllers associated with
+ * this node. This does not delete the controllers themselves!
+ * This should be used very carefully to avoid memory
+ * leaks.
+ */
+
+ void
+ RemoveAllControllers(
+ );
+
+ /// Needed for replication
+
+ /**
+ * Return a reference to this node's controller list.
+ * Whilst we don't wish to expose full control of the container
+ * to the user we do allow them to call non_const methods
+ * on pointers in the container. C++ topic: how to do this in
+ * using STL?
+ */
+
+ SGControllerList&
+ GetSGControllerList(
+ );
+
+
+ /**
+ * Get the client object associated with this
+ * node. This interface allows you to associate
+ * arbitray external objects with this node. They are
+ * passed to the callback functions when they are
+ * activated so you can syncronise these external objects
+ * upon replication and destruction
+ * This may be NULL.
+ */
+
+ void*
+ GetSGClientObject(
+ );
+
+ const
+ void*
+ GetSGClientObject(
+ ) const ;
+
+
+ /**
+ * Set the client object for this node. This is just a
+ * pointer to an object allocated that should exist for
+ * the duration of the lifetime of this object, or untill
+ * this function is called again.
+ */
+
+ void
+ SetSGClientObject(
+ void* clientObject
+ );
+
+ /**
+ * Set the current simulation time for this node.
+ * The implementation of this function runs through
+ * the nodes list of controllers and calls their SetSimulatedTime methods
+ */
+
+ void
+ SetControllerTime(
+ double time
+ );
+
+ virtual
+ void
+ Destruct(
+ ) = 0;
+
+protected :
+
+ void
+ ActivateReplicationCallback(
+ SG_IObject *replica
+ );
+
+ void
+ ActivateDestructionCallback(
+ );
+
+ void
+ ActivateUpdateTransformCallback(
+ );
+
+ SG_IObject(
+ void* clientobj,
+ void* clientinfo,
+ SG_Callbacks callbacks
+ );
+
+ SG_IObject(
+ const SG_IObject &other
+ );
+
+
+};
+
+#endif //__SG_IOBJECT
+
diff --git a/source/gameengine/SceneGraph/SG_Node.cpp b/source/gameengine/SceneGraph/SG_Node.cpp
new file mode 100644
index 00000000000..aaacd43646b
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_Node.cpp
@@ -0,0 +1,239 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SG_Node.h"
+#include "SG_ParentRelation.h"
+#include <algorithm>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+using namespace std;
+
+
+SG_Node::SG_Node(
+ void* clientobj,
+ void* clientinfo,
+ SG_Callbacks callbacks
+
+)
+ : SG_Spatial(clientobj,clientinfo,callbacks),
+ m_SGparent(NULL)
+{
+}
+
+SG_Node::SG_Node(
+ const SG_Node & other
+) :
+ SG_Spatial(other),
+ m_children(other.m_children),
+ m_SGparent(other.m_SGparent)
+{
+ // nothing to do
+}
+
+SG_Node::~SG_Node()
+{
+}
+
+
+SG_Node* SG_Node::GetSGReplica()
+{
+ SG_Node* replica = new SG_Node(*this);
+ if (replica == NULL) return NULL;
+
+ ProcessSGReplica(replica);
+
+ return replica;
+}
+
+ void
+SG_Node::
+ProcessSGReplica(
+ SG_Node* replica
+){
+ // Apply the replication call back function.
+ ActivateReplicationCallback(replica);
+
+ // clear the replica node of it's parent.
+ static_cast<SG_Node*>(replica)->m_SGparent = NULL;
+
+ if (m_children.begin() != m_children.end())
+ {
+ // if this node has children, the replica has too, so clear and clone children
+ replica->ClearSGChildren();
+
+ NodeList::iterator childit;
+ for (childit = m_children.begin();childit!=m_children.end();++childit)
+ {
+ replica->AddChild((*childit)->GetSGReplica());
+ }
+ }
+}
+
+
+ void
+SG_Node::
+Destruct()
+{
+ // Not entirely sure what Destruct() expects to happen.
+ // I think it probably means just to call the DestructionCallback
+ // in the right order on all the children - rather than free any memory
+
+ // We'll delete m_parent_relation now anyway.
+
+ delete(m_parent_relation);
+ m_parent_relation = NULL;
+
+ if (m_children.begin() != m_children.end())
+ {
+ NodeList::iterator childit;
+ for (childit = m_children.begin();childit!=m_children.end();++childit)
+ {
+ // call the SG_Node destruct method on each of our children }-)
+ (*childit)->Destruct();
+ }
+ }
+
+ ActivateDestructionCallback();
+}
+
+
+ SG_Node*
+SG_Node::
+GetSGParent(
+) const {
+ return m_SGparent;
+}
+
+ void
+SG_Node::
+SetSGParent(
+ SG_Node* parent
+){
+ m_SGparent = parent;
+}
+
+const
+ SG_Node*
+SG_Node::
+GetRootSGParent(
+) const {
+ return (m_SGparent ? (const SG_Node*) m_SGparent->GetRootSGParent() : (const SG_Node*) this);
+}
+
+
+ void
+SG_Node::
+DisconnectFromParent(
+){
+ if (m_SGparent)
+ {
+ m_SGparent->RemoveChild(this);
+ m_SGparent = NULL;
+ }
+
+}
+
+
+
+void SG_Node::AddChild(SG_Node* child)
+{
+ m_children.push_back(child);
+ child->SetSGParent(this); // this way ?
+}
+
+void SG_Node::RemoveChild(SG_Node* child)
+{
+ NodeList::iterator childfound = find(m_children.begin(),m_children.end(),child);
+
+ if (childfound != m_children.end())
+ {
+ m_children.erase(childfound);
+ }
+}
+
+
+
+void SG_Node::UpdateWorldData(double time)
+{
+ //if (!GetSGParent())
+ // return;
+
+ if (UpdateSpatialData(GetSGParent(),time))
+ ActivateUpdateTransformCallback();
+
+ // update children's worlddata
+ for (NodeList::iterator it = m_children.begin();it!=m_children.end();++it)
+ {
+ (*it)->UpdateWorldData(time);
+ }
+}
+
+
+NodeList& SG_Node::GetSGChildren()
+{
+ return this->m_children;
+}
+
+
+const NodeList& SG_Node::GetSGChildren() const
+{
+ return this->m_children;
+}
+
+
+void SG_Node::ClearSGChildren()
+{
+ m_children.clear();
+}
+
+
+
+void SG_Node::SetSimulatedTime(double time,bool recurse)
+{
+
+ // update the controllers of this node.
+ SetControllerTime(time);
+
+ // update children's simulate time.
+ if (recurse)
+ {
+ for (NodeList::iterator it = m_children.begin();it!=m_children.end();++it)
+ {
+ (*it)->SetSimulatedTime(time,recurse);
+ }
+ }
+}
+
+
+
diff --git a/source/gameengine/SceneGraph/SG_Node.h b/source/gameengine/SceneGraph/SG_Node.h
new file mode 100644
index 00000000000..7ba13cc0a87
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_Node.h
@@ -0,0 +1,211 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __SG_NODE_H
+#define __SG_NODE_H
+
+#include "SG_Spatial.h"
+#include <vector>
+
+typedef std::vector<SG_Node*> NodeList;
+
+/**
+ * Scenegraph node.
+ */
+class SG_Node : public SG_Spatial
+{
+public:
+
+ SG_Node(
+ void* clientobj,
+ void* clientinfo,
+ SG_Callbacks callbacks
+ );
+
+ SG_Node(
+ const SG_Node & other
+ );
+
+ virtual ~SG_Node();
+
+
+ /**
+ * Add a child to this object. This also informs the child of
+ * it's parent.
+ * This just stores a pointer to the child and does not
+ * make a deep copy.
+ */
+
+ void
+ AddChild(
+ SG_Node* child
+ );
+
+ /**
+ * Remove a child node from this object. This just removes the child
+ * pointer from the list of children - it does not destroy the child.
+ * This does not inform the child that this node is no longer it's parent.
+ * If the node was not a child of this object no action is performed.
+ */
+
+ void
+ RemoveChild(
+ SG_Node* child
+ );
+
+ /**
+ * Get the current list of children. Do not use this interface for
+ * adding or removing children please use the methods of this class for
+ * that.
+ * @return a reference to the list of children of this node.
+ */
+
+ NodeList&
+ GetSGChildren(
+ );
+
+ /**
+ * Get the current list of children.
+ * @return a const reference to the current list of children of this node.
+ */
+
+ const
+ NodeList&
+ GetSGChildren(
+ ) const;
+
+ /**
+ * Clear the list of children associated with this node
+ */
+
+ void
+ ClearSGChildren(
+ );
+
+ /**
+ * return the parent of this node if it exists.
+ */
+
+ SG_Node*
+ GetSGParent(
+ ) const ;
+
+
+ /**
+ * Set the parent of this node.
+ */
+
+ void
+ SetSGParent(
+ SG_Node* parent
+ );
+
+ /**
+ * Return the top node in this node's Scene graph hierarchy
+ */
+
+ const
+ SG_Node*
+ GetRootSGParent(
+ ) const;
+
+ /**
+ * Disconnect this node from it's parent
+ */
+
+ void
+ DisconnectFromParent(
+ );
+
+ /**
+ * Tell this node to treat it's parent as a vertex parent.
+ */
+
+ void
+ SetVertexParent(
+ bool isvertexparent
+ ) ;
+
+
+ /**
+ * Update the spatial data of this node. Iterate through
+ * the children of this node and update their world data.
+ */
+
+ void
+ UpdateWorldData(
+ double time
+ );
+
+ /**
+ * Update the simulation time of this node. Iterate through
+ * the children nodes and update their simulated time.
+ */
+
+ void
+ SetSimulatedTime(
+ double time,
+ bool recurse
+ );
+
+ /**
+ * Node replication functions.
+ */
+
+ SG_Node*
+ GetSGReplica(
+ );
+
+ void
+ Destruct(
+ );
+
+private:
+
+ void
+ ProcessSGReplica(
+ SG_Node* replica
+ );
+
+ /**
+ * The list of children of this node.
+ */
+ NodeList m_children;
+
+ /**
+ * The parent of this node may be NULL
+ */
+ SG_Node* m_SGparent;
+
+};
+
+#endif //__SG_NODE_H
+
diff --git a/source/gameengine/SceneGraph/SG_ParentRelation.h b/source/gameengine/SceneGraph/SG_ParentRelation.h
new file mode 100644
index 00000000000..d4a8e7e8cb3
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_ParentRelation.h
@@ -0,0 +1,117 @@
+/**
+ * @mainpage SG_ParentRelation
+
+ * @section
+ *
+ * This is an abstract interface class to the Scene Graph library.
+ * It allows you to specify how child nodes react to parent nodes.
+ * Normally a child will use it's parent's transforms to compute
+ * it's own global transforms. How this is performed depends on
+ * the type of relation. For example if the parent is a vertex
+ * parent to this child then the child should not inherit any
+ * rotation information from the parent. Or if the parent is a
+ * 'slow parent' to this child then the child should react
+ * slowly to changes in the parent's position. The exact relation
+ * is left for you to implement by filling out this interface
+ * with concrete examples.
+ *
+ * There is exactly one SG_ParentRelation per SG_Node. Subclasses
+ * should not be value types and should be allocated on the heap.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __SG_ParentRelation_h
+#define __SG_ParentRelation_h
+
+class SG_Spatial;
+
+class SG_ParentRelation {
+
+public :
+
+ /**
+ * Update the childs local and global coordinates
+ * based upon the parents global coordinates.
+ * You must also handle the case when this node has no
+ * parent (parent == NULL). Usually you should just
+ * copy the local coordinates of the child to the
+ * world coordinates.
+ */
+
+ virtual
+ bool
+ UpdateChildCoordinates(
+ SG_Spatial * child,
+ const SG_Spatial * parent
+ ) = 0;
+
+ virtual
+ ~SG_ParentRelation(
+ ){
+ };
+
+ /**
+ * You must provide a way of duplicating an
+ * instance of an SG_ParentRelation. This should
+ * return a pointer to a new duplicate allocated
+ * on the heap. Responsibilty for deleting the
+ * duplicate resides with the caller of this method.
+ */
+
+ virtual
+ SG_ParentRelation *
+ NewCopy(
+ ) = 0;
+
+protected :
+
+ /**
+ * Protected constructors
+ * this class is not meant to be instantiated.
+ */
+
+ SG_ParentRelation(
+ ) {
+ };
+
+ /**
+ * Copy construction should not be implemented
+ */
+
+ SG_ParentRelation(
+ const SG_ParentRelation &
+ );
+};
+
+#endif
+
diff --git a/source/gameengine/SceneGraph/SG_Spatial.cpp b/source/gameengine/SceneGraph/SG_Spatial.cpp
new file mode 100644
index 00000000000..6ad5cf9912a
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_Spatial.cpp
@@ -0,0 +1,330 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 "SG_Node.h"
+#include "SG_Spatial.h"
+#include "SG_Controller.h"
+#include "SG_ParentRelation.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+SG_Spatial::
+SG_Spatial(
+ void* clientobj,
+ void* clientinfo,
+ SG_Callbacks callbacks
+):
+
+ SG_IObject(clientobj,clientinfo,callbacks),
+ m_localPosition(MT_Point3(0.0,0.0,0.0)),
+ m_localRotation(MT_Matrix3x3(1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0)),
+ m_localScaling(MT_Vector3(1.f,1.f,1.f)),
+
+ m_worldPosition(MT_Point3(0.0,0.0,0.0)),
+ m_worldRotation(MT_Matrix3x3(1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0)),
+ m_worldScaling(MT_Vector3(1.f,1.f,1.f)),
+
+ m_parent_relation (NULL),
+
+ m_bbox(MT_Point3(-1.0, -1.0, -1.0), MT_Point3(1.0, 1.0, 1.0)),
+ m_radius(1.0)
+{
+}
+
+SG_Spatial::
+SG_Spatial(
+ const SG_Spatial& other
+) :
+ SG_IObject(other),
+ m_localPosition(other.m_localPosition),
+ m_localRotation(other.m_localRotation),
+ m_localScaling(other.m_localScaling),
+
+ m_worldPosition(other.m_worldPosition),
+ m_worldRotation(other.m_worldRotation),
+ m_worldScaling(other.m_worldScaling),
+
+ m_parent_relation(NULL),
+
+ m_bbox(other.m_bbox),
+ m_radius(other.m_radius)
+{
+ // duplicate the parent relation for this object
+ m_parent_relation = other.m_parent_relation->NewCopy();
+}
+
+SG_Spatial::
+~SG_Spatial()
+{
+ delete (m_parent_relation);
+}
+
+ void
+SG_Spatial::
+SetParentRelation(
+ SG_ParentRelation *relation
+){
+ delete (m_parent_relation);
+ m_parent_relation = relation;
+}
+
+
+/**
+ * Update Spatial Data.
+ * Calculates WorldTransform., (either doing itsself or using the linked SGControllers)
+ */
+
+
+ bool
+SG_Spatial::
+UpdateSpatialData(
+ const SG_Spatial *parent,
+ double time
+){
+
+ bool bComputesWorldTransform = false;
+
+ // update spatial controllers
+
+ SGControllerList::iterator cit = GetSGControllerList().begin();
+ SGControllerList::const_iterator c_end = GetSGControllerList().end();
+
+ for (;cit!=c_end;++cit)
+ {
+ if ((*cit)->Update(time))
+ bComputesWorldTransform = true;
+ }
+
+ // If none of the objects updated our values then we ask the
+ // parent_relation object owned by this class to update
+ // our world coordinates.
+
+ if (!bComputesWorldTransform)
+ bComputesWorldTransform = ComputeWorldTransforms(parent);
+
+ return bComputesWorldTransform;
+}
+
+bool SG_Spatial::ComputeWorldTransforms(const SG_Spatial *parent)
+{
+ return m_parent_relation->UpdateChildCoordinates(this,parent);
+}
+
+/**
+ * Position and translation methods
+ */
+
+
+ void
+SG_Spatial::
+RelativeTranslate(
+ const MT_Vector3& trans,
+ const SG_Spatial *parent,
+ bool local
+){
+ if (local) {
+ m_localPosition += m_localRotation * trans;
+ } else {
+ if (parent) {
+ m_localPosition += trans * parent->GetWorldOrientation();
+ } else {
+ m_localPosition += trans;
+ }
+ }
+}
+
+ void
+SG_Spatial::
+SetLocalPosition(
+ const MT_Point3& trans
+){
+ m_localPosition = trans;
+}
+
+ void
+SG_Spatial::
+SetWorldPosition(
+ const MT_Point3& trans
+) {
+ m_worldPosition = trans;
+}
+
+/**
+ * Scaling methods.
+ */
+
+ void
+SG_Spatial::
+RelativeScale(
+ const MT_Vector3& scale
+){
+ m_localScaling = m_localScaling * scale;
+}
+
+ void
+SG_Spatial::
+SetLocalScale(
+ const MT_Vector3& scale
+){
+ m_localScaling = scale;
+}
+
+
+ void
+SG_Spatial::
+SetWorldScale(
+ const MT_Vector3& scale
+){
+ m_worldScaling = scale;
+}
+
+/**
+ * Orientation and rotation methods.
+ */
+
+
+ void
+SG_Spatial::
+RelativeRotate(
+ const MT_Matrix3x3& rot,
+ bool local
+){
+ m_localRotation = m_localRotation * (
+ local ?
+ rot
+ :
+ (GetWorldOrientation().inverse() * rot * GetWorldOrientation()));
+}
+
+ void
+SG_Spatial::
+SetLocalOrientation(const MT_Matrix3x3& rot)
+{
+ m_localRotation = rot;
+}
+
+
+
+ void
+SG_Spatial::
+SetWorldOrientation(
+ const MT_Matrix3x3& rot
+) {
+ m_worldRotation = rot;
+}
+
+const
+ MT_Point3&
+SG_Spatial::
+GetLocalPosition(
+) const {
+ return m_localPosition;
+}
+
+const
+ MT_Matrix3x3&
+SG_Spatial::
+GetLocalOrientation(
+) const {
+ return m_localRotation;
+}
+
+const
+ MT_Vector3&
+SG_Spatial::
+GetLocalScale(
+) const{
+ return m_localScaling;
+}
+
+
+const
+ MT_Point3&
+SG_Spatial::
+GetWorldPosition(
+) const {
+ return m_worldPosition;
+}
+
+const
+ MT_Matrix3x3&
+SG_Spatial::
+GetWorldOrientation(
+) const {
+ return m_worldRotation;
+}
+
+const
+ MT_Vector3&
+SG_Spatial::
+GetWorldScaling(
+) const {
+ return m_worldScaling;
+}
+
+SG_BBox& SG_Spatial::BBox()
+{
+ return m_bbox;
+}
+
+void SG_Spatial::SetBBox(SG_BBox& bbox)
+{
+ m_bbox = bbox;
+}
+
+MT_Transform SG_Spatial::GetWorldTransform() const
+{
+ return MT_Transform(m_worldPosition,
+ m_worldRotation.scaled(
+ m_worldScaling[0], m_worldScaling[1], m_worldScaling[2]));
+}
+
+bool SG_Spatial::inside(const MT_Point3 &point) const
+{
+ MT_Scalar radius = m_worldScaling[m_worldScaling.closestAxis()]*m_radius;
+ return (m_worldPosition.distance2(point) <= radius*radius) ?
+ m_bbox.transform(GetWorldTransform()).inside(point) :
+ false;
+}
+
+void SG_Spatial::getBBox(MT_Point3 *box) const
+{
+ m_bbox.get(box, GetWorldTransform());
+}
+
+void SG_Spatial::getAABBox(MT_Point3 *box) const
+{
+ m_bbox.getaa(box, GetWorldTransform());
+}
+
diff --git a/source/gameengine/SceneGraph/SG_Spatial.h b/source/gameengine/SceneGraph/SG_Spatial.h
new file mode 100644
index 00000000000..1f1e97a5b56
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_Spatial.h
@@ -0,0 +1,229 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 __SG_SPATIAL_H
+#define __SG_SPATIAL_H
+
+#include <MT_Vector3.h>
+#include <MT_Point3.h>
+#include <MT_Matrix3x3.h> // or Quaternion later ?
+#include "SG_IObject.h"
+#include "SG_BBox.h"
+
+
+class SG_Node;
+class SG_ParentRelation;
+
+/**
+ * SG_Spatial contains spatial information (local & world position, rotation
+ * and scaling) for a Scene graph node.
+ * It also contains a link to the node's parent.
+ */
+class SG_Spatial : public SG_IObject
+{
+
+protected:
+ MT_Point3 m_localPosition;
+ MT_Matrix3x3 m_localRotation;
+ MT_Vector3 m_localScaling;
+
+ MT_Point3 m_worldPosition;
+ MT_Matrix3x3 m_worldRotation;
+ MT_Vector3 m_worldScaling;
+
+ SG_ParentRelation * m_parent_relation;
+
+ SG_BBox m_bbox;
+ MT_Scalar m_radius;
+
+
+public:
+
+ /**
+ * Define the realtionship this node has with it's parent
+ * node. You should pass an unshared instance of an SG_ParentRelation
+ * allocated on the heap to this method. Ownership of this
+ * instance is assumed by this class.
+ * You may call this function several times in the lifetime
+ * of a node to change the relationship dynamically.
+ * You must call this method before the first call to UpdateSpatialData().
+ * An assertion willl be fired at run-time in debug if this is not
+ * the case.
+ * The relation is activated only if no controllers of this object
+ * updated the coordinates of the child.
+ */
+
+ void
+ SetParentRelation(
+ SG_ParentRelation *relation
+ );
+
+
+ /**
+ * Apply a translation relative to the current position.
+ * if local then the translation is assumed to be in the
+ * local coordinates of this object. If not then the translation
+ * is assumed to be in global coordinates. In this case
+ * you must provide a pointer to the parent of this object if it
+ * exists otherwise if there is no parent set it to NULL
+ */
+
+ void
+ RelativeTranslate(
+ const MT_Vector3& trans,
+ const SG_Spatial *parent,
+ bool local
+ );
+
+ void
+ SetLocalPosition(
+ const MT_Point3& trans
+ );
+
+ void
+ SetWorldPosition(
+ const MT_Point3& trans
+ );
+
+ void
+ RelativeRotate(
+ const MT_Matrix3x3& rot,
+ bool local
+ );
+
+ void
+ SetLocalOrientation(
+ const MT_Matrix3x3& rot
+ );
+
+ void
+ SetWorldOrientation(
+ const MT_Matrix3x3& rot
+ );
+
+ void
+ RelativeScale(
+ const MT_Vector3& scale
+ );
+
+ void
+ SetLocalScale(
+ const MT_Vector3& scale
+ );
+
+ void
+ SetWorldScale(
+ const MT_Vector3& scale
+ );
+
+ const
+ MT_Point3&
+ GetLocalPosition(
+ ) const ;
+
+ const
+ MT_Matrix3x3&
+ GetLocalOrientation(
+ ) const ;
+
+ const
+ MT_Vector3&
+ GetLocalScale(
+ ) const;
+
+ const
+ MT_Point3&
+ GetWorldPosition(
+ ) const ;
+
+ const
+ MT_Matrix3x3&
+ GetWorldOrientation(
+ ) const ;
+
+ const
+ MT_Vector3&
+ GetWorldScaling(
+ ) const ;
+
+ MT_Transform GetWorldTransform() const;
+
+ bool ComputeWorldTransforms( const SG_Spatial *parent);
+
+ /**
+ * Bounding box functions.
+ */
+ SG_BBox& BBox();
+ void SetBBox(SG_BBox & bbox);
+ bool inside(const MT_Point3 &point) const;
+ void getBBox(MT_Point3 *box) const;
+ void getAABBox(MT_Point3 *box) const;
+
+ MT_Scalar Radius() const { return m_radius; }
+ void SetRadius(MT_Scalar radius) { m_radius = radius; }
+
+protected:
+ friend class SG_Controller;
+
+ /**
+ * Protected constructor this class is not
+ * designed for direct instantiation
+ */
+
+ SG_Spatial(
+ void* clientobj,
+ void* clientinfo,
+ SG_Callbacks callbacks
+ );
+
+ SG_Spatial(
+ const SG_Spatial& other
+ );
+
+
+ virtual ~SG_Spatial();
+
+ /**
+ * Update the world coordinates of this spatial node. This also informs
+ * any controllers to update this object.
+ */
+
+ bool
+ UpdateSpatialData(
+ const SG_Spatial *parent,
+ double time
+ );
+
+};
+
+#endif //__SG_SPATIAL_H
+
diff --git a/source/gameengine/SceneGraph/SG_Tree.cpp b/source/gameengine/SceneGraph/SG_Tree.cpp
new file mode 100644
index 00000000000..0bad621ff07
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_Tree.cpp
@@ -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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Bounding Box
+ */
+
+#include <math.h>
+
+#include "SG_BBox.h"
+#include "SG_Tree.h"
+#include "SG_Node.h"
+
+SG_Tree::SG_Tree()
+{
+}
+
+SG_Tree::SG_Tree(SG_Tree* left, SG_Tree* right) :
+ m_left(left),
+ m_right(right),
+ m_client_object(NULL)
+{
+ if (m_left)
+ {
+ m_bbox = m_left->m_bbox;
+ m_left->m_parent = this;
+ }
+ if (m_right)
+ {
+ m_bbox += m_right->m_bbox;
+ m_right->m_parent = this;
+ }
+ m_center = (m_bbox.m_min + m_bbox.m_max)/2.0;
+ m_radius = (m_bbox.m_max - m_bbox.m_min).length();
+}
+
+SG_Tree::SG_Tree(SG_Node* client) :
+ m_left(NULL),
+ m_right(NULL),
+ m_client_object(client)
+{
+ m_bbox = SG_BBox(client->BBox(), client->GetWorldTransform());
+ m_center = (m_bbox.m_min + m_bbox.m_max)/2.0;
+ m_radius = (m_bbox.m_max - m_bbox.m_min).length();
+}
+
+SG_Tree::~SG_Tree()
+{
+}
+
+MT_Scalar SG_Tree::volume() const
+{
+ return m_bbox.volume();
+}
+
+void SG_Tree::dump() const
+{
+ if (m_left)
+ m_left->dump();
+ if (m_client_object)
+ std::cout << m_client_object << std::endl;
+ else
+ std::cout << this << " ";
+ if (m_right)
+ m_right->dump();
+}
+
+SG_Tree* SG_Tree::Left() const
+{
+ return m_left;
+}
+
+SG_Tree* SG_Tree::Right() const
+{
+ return m_right;
+}
+
+SG_Node* SG_Tree::Client() const
+{
+ return m_client_object;
+}
+
+SG_Tree* SG_Tree::Find(SG_Node *node)
+{
+ if (m_client_object == node)
+ return this;
+
+ SG_Tree *left = m_left, *right = m_right;
+
+ if (left && right)
+ {
+ if (right->m_bbox.intersects(node->BBox()))
+ std::swap(left, right);
+ }
+
+ if (left)
+ {
+ SG_Tree* ret = left->Find(node);
+ if (ret) return ret;
+ }
+
+ if (right)
+ {
+ SG_Tree* ret = right->Find(node);
+ if (ret) return ret;
+ }
+
+ return NULL;
+}
+
+void SG_Tree::get(MT_Point3 *box) const
+{
+ MT_Transform identity;
+ identity.setIdentity();
+ m_bbox.get(box, identity);
+}
+
+bool SG_Tree::inside(const MT_Point3 &point) const
+{
+ return m_bbox.inside(point);
+}
+
+const SG_BBox& SG_Tree::BBox() const
+{
+ return m_bbox;
+}
+
+void SG_Tree::SetLeft(SG_Tree *left)
+{
+ m_left = left;
+ m_bbox += left->m_bbox;
+ m_center = (m_bbox.m_min + m_bbox.m_max)/2.0;
+ m_radius = (m_bbox.m_max - m_bbox.m_min).length();
+}
+
+void SG_Tree::SetRight(SG_Tree *right)
+{
+ m_right = right;
+ m_bbox += right->m_bbox;
+ m_center = (m_bbox.m_min + m_bbox.m_max)/2.0;
+ m_radius = (m_bbox.m_max - m_bbox.m_min).length();
+}
+
+/**
+ * A Half array is a square 2d array where cell(x, y) is undefined
+ * if x < y.
+ */
+template<typename T>
+class HalfArray
+{
+ std::vector<std::vector<T> > m_array;
+public:
+ HalfArray() {}
+ ~HalfArray() {}
+
+ void resize(unsigned int size)
+ {
+ m_array.resize(size);
+ for( unsigned int i = 0; i < size; i++)
+ {
+ m_array[i].resize(size - i);
+ }
+ }
+
+ T& operator() (unsigned int x, unsigned int y)
+ {
+ assert(x >= y);
+ return m_array[y][x - y];
+ }
+
+ void erase_column (unsigned int x)
+ {
+ for (unsigned int y = 0; y <= x; y++)
+ m_array[y].erase(m_array[y].begin() + x - y);
+ }
+
+ void delete_column (unsigned int x)
+ {
+ for (unsigned int y = 0; y < x; y++)
+ {
+ delete m_array[y][x - y];
+ m_array[y].erase(m_array[y].begin() + x - y);
+ }
+ }
+
+ void erase_row (unsigned int y)
+ {
+ m_array.erase(m_array.begin() + y);
+ }
+};
+
+SG_TreeFactory::SG_TreeFactory()
+{
+}
+
+SG_TreeFactory::~SG_TreeFactory()
+{
+}
+
+void SG_TreeFactory::Add(SG_Node* client)
+{
+ if (client)
+ m_objects.insert(new SG_Tree(client));
+}
+
+void SG_TreeFactory::Add(SG_Tree* tree)
+{
+ m_objects.insert(tree);
+}
+
+SG_Tree* SG_TreeFactory::MakeTreeDown(SG_BBox &bbox)
+{
+ if (m_objects.size() == 0)
+ return NULL;
+ if (m_objects.size() == 1)
+ return *m_objects.begin();
+
+ TreeSet::iterator it = m_objects.begin();
+ SG_Tree *root = *it;
+ if (m_objects.size() == 2)
+ {
+ root->SetRight(*(++it));
+ return root;
+ }
+
+ if (m_objects.size() == 3)
+ {
+ root->SetLeft(*(++it));
+ root->SetRight(*(++it));
+ return root;
+ }
+
+ if (bbox.volume() < 1.0)
+ return MakeTreeUp();
+
+ SG_TreeFactory lefttree;
+ SG_TreeFactory righttree;
+
+ SG_BBox left, right;
+ int hasleft = 0, hasright = 0;
+ bbox.split(left, right);
+
+ if (left.test(root->BBox()) == SG_BBox::INSIDE)
+ {
+ lefttree.Add(root);
+ root = NULL;
+ }
+
+ if (root && right.test(root->BBox()) == SG_BBox::INSIDE)
+ {
+ righttree.Add(root);
+ root = NULL;
+ }
+
+ for (++it; it != m_objects.end(); ++it)
+ {
+ switch (left.test((*it)->BBox()))
+ {
+ case SG_BBox::INSIDE:
+ // Object is inside left tree;
+ lefttree.Add(*it);
+ hasleft++;
+ break;
+ case SG_BBox::OUTSIDE:
+ righttree.Add(*it);
+ hasright++;
+ break;
+ case SG_BBox::INTERSECT:
+ if (left.inside((*it)->Client()->GetWorldPosition()))
+ {
+ lefttree.Add(*it);
+ hasleft++;
+ } else {
+ righttree.Add(*it);
+ hasright++;
+ }
+ break;
+ }
+ }
+ std::cout << "Left: " << hasleft << " Right: " << hasright << " Count: " << m_objects.size() << std::endl;
+
+ SG_Tree *leftnode = NULL;
+ if (hasleft)
+ leftnode = lefttree.MakeTreeDown(left);
+
+ SG_Tree *rightnode = NULL;
+ if (hasright)
+ rightnode = righttree.MakeTreeDown(right);
+
+ if (!root)
+ root = new SG_Tree(leftnode, rightnode);
+ else
+ {
+ if (leftnode)
+ root->SetLeft(leftnode);
+ if (rightnode)
+ root->SetRight(rightnode);
+ }
+
+ return root;
+}
+
+SG_Tree* SG_TreeFactory::MakeTree()
+{
+ if (m_objects.size() < 8)
+ return MakeTreeUp();
+
+ TreeSet::iterator it = m_objects.begin();
+ SG_BBox bbox((*it)->BBox());
+ for (++it; it != m_objects.end(); ++it)
+ bbox += (*it)->BBox();
+
+ return MakeTreeDown(bbox);
+}
+
+SG_Tree* SG_TreeFactory::MakeTreeUp()
+{
+ unsigned int num_objects = m_objects.size();
+
+ if (num_objects < 1)
+ return NULL;
+ if (num_objects < 2)
+ return *m_objects.begin();
+
+ HalfArray<SG_Tree*> sizes;
+ sizes.resize(num_objects);
+
+ unsigned int x, y;
+ TreeSet::iterator xit, yit;
+ for( y = 0, yit = m_objects.begin(); y < num_objects; y++, ++yit)
+ {
+ sizes(y, y) = *yit;
+ xit = yit;
+ for( x = y+1, ++xit; x < num_objects; x++, ++xit)
+ {
+ sizes(x, y) = new SG_Tree(*xit, *yit);
+
+ }
+ }
+ while (num_objects > 2)
+ {
+ /* Find the pair of bboxes that produce the smallest combined bbox. */
+ unsigned int minx = UINT_MAX, miny = UINT_MAX;
+ MT_Scalar min_volume = FLT_MAX;
+ SG_Tree *min = NULL;
+ //char temp[16];
+ for( y = 0; y < num_objects; y++)
+ {
+ for( x = y+1; x < num_objects; x++)
+ {
+ if (sizes(x, y)->volume() < min_volume)
+ {
+ min = sizes(x, y);
+ minx = x;
+ miny = y;
+ min_volume = sizes(x, y)->volume();
+ }
+ }
+ }
+
+ /* Remove other bboxes that contain the two bboxes */
+ sizes.delete_column(miny);
+
+ for( x = miny + 1; x < num_objects; x++)
+ {
+ if (x == minx)
+ continue;
+ delete sizes(x, miny);
+ }
+ sizes.erase_row(miny);
+
+ num_objects--;
+ minx--;
+ sizes(minx, minx) = min;
+ for( x = minx + 1; x < num_objects; x++)
+ {
+ delete sizes(x, minx);
+ sizes(x, minx) = new SG_Tree(min, sizes(x, x));
+ }
+ for( y = 0; y < minx; y++)
+ {
+ delete sizes(minx, y);
+ sizes(minx, y) = new SG_Tree(sizes(y, y), min);
+ }
+ }
+ return sizes(1, 0);
+}
+
diff --git a/source/gameengine/SceneGraph/SG_Tree.h b/source/gameengine/SceneGraph/SG_Tree.h
new file mode 100644
index 00000000000..0877668c53d
--- /dev/null
+++ b/source/gameengine/SceneGraph/SG_Tree.h
@@ -0,0 +1,156 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Bounding Box
+ */
+
+#ifndef __SG_TREE_H__
+#define __SG_TREE_H__
+
+#include "MT_Point3.h"
+#include "SG_BBox.h"
+
+#include <set>
+
+class SG_Node;
+
+
+/**
+ * SG_Tree.
+ * Holds a binary tree of SG_Nodes.
+ */
+class SG_Tree
+{
+ SG_Tree* m_left;
+ SG_Tree* m_right;
+ SG_Tree* m_parent;
+ SG_BBox m_bbox;
+ MT_Point3 m_center;
+ MT_Scalar m_radius;
+ SG_Node* m_client_object;
+public:
+ SG_Tree();
+ SG_Tree(SG_Tree* left, SG_Tree* right);
+
+ SG_Tree(SG_Node* client);
+ ~SG_Tree();
+
+ /**
+ * Computes the volume of the bounding box.
+ */
+ MT_Scalar volume() const;
+
+ /**
+ * Prints the tree (for debugging.)
+ */
+ void dump() const;
+
+ /**
+ * Returns the left node.
+ */
+ SG_Tree *Left() const;
+ SG_Tree *Right() const;
+ SG_Node *Client() const;
+
+ SG_Tree* Find(SG_Node *node);
+ /**
+ * Gets the eight corners of this treenode's bounding box,
+ * in world coordinates.
+ * @param box: an array of 8 MT_Point3
+ * @example MT_Point3 box[8];
+ * treenode->get(box);
+ */
+ void get(MT_Point3 *box) const;
+ /**
+ * Get the tree node's bounding box.
+ */
+ const SG_BBox& BBox() const;
+
+ /**
+ * Test if the given bounding box is inside this bounding box.
+ */
+ bool inside(const MT_Point3 &point) const;
+
+ void SetLeft(SG_Tree *left);
+ void SetRight(SG_Tree *right);
+
+ MT_Point3 Center() const { return m_center; }
+ MT_Scalar Radius() { return m_radius; }
+
+ //friend class SG_TreeFactory;
+
+ struct greater
+ {
+ bool operator()(const SG_Tree *a, const SG_Tree *b)
+ {
+ return a->volume() > b->volume();
+ }
+ };
+
+};
+
+
+/**
+ * SG_TreeFactory generates an SG_Tree from a list of SG_Nodes.
+ * It joins pairs of SG_Nodes to minimise the size of the resultant
+ * bounding box.
+ * cf building an optimised Huffman tree.
+ * @warning O(n^3)!!!
+ */
+class SG_TreeFactory
+{
+ typedef std::multiset<SG_Tree*, SG_Tree::greater> TreeSet;
+ TreeSet m_objects;
+public:
+ SG_TreeFactory();
+ ~SG_TreeFactory();
+
+ /**
+ * Add a node to be added to the tree.
+ */
+ void Add(SG_Node* client);
+ void Add(SG_Tree* tree);
+
+ /**
+ * Build the tree from the set of nodes added by
+ * the Add method.
+ */
+ SG_Tree* MakeTreeUp();
+
+ /**
+ * Build the tree from the set of nodes top down.
+ */
+ SG_Tree* MakeTreeDown(SG_BBox &bbox);
+
+ SG_Tree* MakeTree();
+
+};
+
+#endif /* __SG_BBOX_H__ */
diff --git a/source/icons/Makefile b/source/icons/Makefile
new file mode 100644
index 00000000000..684c2eefb28
--- /dev/null
+++ b/source/icons/Makefile
@@ -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 *****
+#
+#
+
+DIR = $(OCGDIR)/blender/icons
+
+include nan_compile.mk
+
+clean::
+ @$(RM) $(DIR)/*.res $(DIR)/debug/*.res
diff --git a/source/icons/SConscript b/source/icons/SConscript
new file mode 100644
index 00000000000..1471a06c09d
--- /dev/null
+++ b/source/icons/SConscript
@@ -0,0 +1,6 @@
+#!/usr/bin/python
+Import ('env')
+
+source = 'winblender.rcscons'
+
+env.BlenderRes('winresource', source, ['core', 'player'], priority=[95 , 100]) \ No newline at end of file
diff --git a/source/icons/winblender.ico b/source/icons/winblender.ico
new file mode 100644
index 00000000000..85fccd71bf5
--- /dev/null
+++ b/source/icons/winblender.ico
Binary files differ
diff --git a/source/icons/winblender.rc b/source/icons/winblender.rc
new file mode 100644
index 00000000000..77e62111d2d
--- /dev/null
+++ b/source/icons/winblender.rc
@@ -0,0 +1,2 @@
+APPICON ICON "winblender.ico"
+BLENDERFILE ICON "winblenderfile.ico"
diff --git a/source/icons/winblender.rcscons b/source/icons/winblender.rcscons
new file mode 100644
index 00000000000..97579f1ffe0
--- /dev/null
+++ b/source/icons/winblender.rcscons
@@ -0,0 +1,2 @@
+APPICON ICON "source\\icons\\winblender.ico"
+BLENDERFILE ICON "source\\icons\\winblenderfile.ico"
diff --git a/source/icons/winblenderfile.ico b/source/icons/winblenderfile.ico
new file mode 100644
index 00000000000..254480b6ed5
--- /dev/null
+++ b/source/icons/winblenderfile.ico
Binary files differ
diff --git a/source/icons/wincreator.ico b/source/icons/wincreator.ico
new file mode 100644
index 00000000000..4fb7be08788
--- /dev/null
+++ b/source/icons/wincreator.ico
Binary files differ
diff --git a/source/icons/wincreator.rc b/source/icons/wincreator.rc
new file mode 100644
index 00000000000..e11bdaf15e3
--- /dev/null
+++ b/source/icons/wincreator.rc
@@ -0,0 +1,2 @@
+APPICON ICON "wincreator.ico"
+BLENDERFILE ICON "winblenderfile.ico"
diff --git a/source/icons/winlockedfile.ico b/source/icons/winlockedfile.ico
new file mode 100644
index 00000000000..8b23d5c3d4d
--- /dev/null
+++ b/source/icons/winlockedfile.ico
Binary files differ
diff --git a/source/icons/winplayer.ico b/source/icons/winplayer.ico
new file mode 100644
index 00000000000..336ff09f94f
--- /dev/null
+++ b/source/icons/winplayer.ico
Binary files differ
diff --git a/source/icons/winplayer.rc b/source/icons/winplayer.rc
new file mode 100644
index 00000000000..e2b255e7280
--- /dev/null
+++ b/source/icons/winplayer.rc
@@ -0,0 +1 @@
+APPICON ICON "winplayer.ico"
diff --git a/source/icons/winpublisher.ico b/source/icons/winpublisher.ico
new file mode 100644
index 00000000000..9a6f4690681
--- /dev/null
+++ b/source/icons/winpublisher.ico
Binary files differ
diff --git a/source/icons/winpublisher.rc b/source/icons/winpublisher.rc
new file mode 100644
index 00000000000..b296c0ffc8f
--- /dev/null
+++ b/source/icons/winpublisher.rc
@@ -0,0 +1,3 @@
+APPICON ICON "winpublisher.ico"
+BLENDERFILE ICON "winblenderfile.ico"
+LOCKEDFILE ICON "winlockedfile.ico"
diff --git a/source/kernel/CMakeLists.txt b/source/kernel/CMakeLists.txt
new file mode 100644
index 00000000000..fbfa7bd0329
--- /dev/null
+++ b/source/kernel/CMakeLists.txt
@@ -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) 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(INC gen_messaging gen_system ../../intern/string ../../intern/moto/include)
+
+FILE(GLOB SRC
+ gen_messaging/intern/messaging.c
+ gen_system/GEN_HashedPtr.cpp
+ gen_system/GEN_Matrix4x4.cpp
+ gen_system/SYS_SingletonSystem.cpp
+ gen_system/SYS_System.cpp
+)
+
+BLENDERLIB(bf_kernel "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_kernel', Split(sources), Split(incs), [], libtype = ['common','game2', 'player'], priority = [15, 10, 150] )
diff --git a/source/kernel/Makefile b/source/kernel/Makefile
new file mode 100644
index 00000000000..51d31f2f6ac
--- /dev/null
+++ b/source/kernel/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 *****
+#
+# Make module object directory and bounce make to subdirectories.
+
+include nan_definitions.mk
+
+DIR = $(OCGDIR)/kernel
+SOURCEDIR = source/kernel
+DIRS = gen_system gen_messaging
+
+include nan_subdirs.mk
diff --git a/source/kernel/SConscript b/source/kernel/SConscript
new file mode 100644
index 00000000000..9e678c041dc
--- /dev/null
+++ b/source/kernel/SConscript
@@ -0,0 +1,10 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = 'gen_messaging/intern/messaging.c gen_system/GEN_HashedPtr.cpp'
+sources += ' gen_system/GEN_Matrix4x4.cpp gen_system/SYS_SingletonSystem.cpp'
+sources += ' gen_system/SYS_System.cpp'
+
+incs = 'gen_messaging gen_system #/intern/string #/intern/moto/include'
+
+env.BlenderLib ( 'bf_kernel', Split(sources), Split(incs), [], libtype = ['common','game2', 'player'], priority = [15, 10, 150] )
diff --git a/source/kernel/gen_messaging/GEN_messaging.h b/source/kernel/gen_messaging/GEN_messaging.h
new file mode 100644
index 00000000000..b4b20c21cd9
--- /dev/null
+++ b/source/kernel/gen_messaging/GEN_messaging.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 GEN_MESSAGING_H
+#define GEN_MESSAGING_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /**
+ * Stream for error messages.
+ */
+ extern FILE* GEN_errorstream;
+
+ /**
+ * Stream for notices to the user.
+ */
+ extern FILE* GEN_userstream;
+
+ /**
+ * Initialise the messaging system. If the system is not
+ * initialised, the streams cannot be used. */
+ void GEN_init_messaging_system(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GEN_MESSAGING_H */
+
diff --git a/source/kernel/gen_messaging/Makefile b/source/kernel/gen_messaging/Makefile
new file mode 100644
index 00000000000..d8420531e05
--- /dev/null
+++ b/source/kernel/gen_messaging/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/kernel/gen_messaging
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/kernel/gen_messaging/intern/Makefile b/source/kernel/gen_messaging/intern/Makefile
new file mode 100644
index 00000000000..8b204800650
--- /dev/null
+++ b/source/kernel/gen_messaging/intern/Makefile
@@ -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.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = gen_messaging
+DIR = $(OCGDIR)/kernel/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+# path to our own external headerfiles
+CPPFLAGS += -I..
+
diff --git a/source/kernel/gen_messaging/intern/messaging.c b/source/kernel/gen_messaging/intern/messaging.c
new file mode 100644
index 00000000000..b5b4cd27481
--- /dev/null
+++ b/source/kernel/gen_messaging/intern/messaging.c
@@ -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 *****
+ * A message and error sink for c and c++
+ */
+
+
+#include "GEN_messaging.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+FILE* GEN_errorstream = NULL;
+FILE* GEN_userstream = NULL;
+
+void GEN_init_messaging_system(void)
+{
+ GEN_errorstream = stderr;
+ GEN_userstream = stdout;
+}
diff --git a/source/kernel/gen_system/GEN_DataCache.h b/source/kernel/gen_system/GEN_DataCache.h
new file mode 100644
index 00000000000..7e4e0127c63
--- /dev/null
+++ b/source/kernel/gen_system/GEN_DataCache.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 __GEN_DATACACHE_H
+#define __GEN_DATACACHE_H
+
+#include "STR_HashedString.h"
+#include "GEN_Map.h"
+
+template <class T>
+class GEN_DataCache
+{
+ GEN_Map<STR_HashedString,T*> m_dataCache;
+ virtual T* LoadData(const STR_String& name)=0;
+ virtual void FreeCacheObjects()=0;
+
+public:
+ GEN_DataCache() {};
+ virtual ~GEN_DataCache() {};
+
+ T* GetData(const STR_String& paramname)
+ {
+ T* result=NULL;
+
+ T** resultptr = m_dataCache[paramname];
+ if (resultptr)
+ {
+ result = *resultptr;
+ }
+
+ else
+ {
+ result = LoadData(paramname);
+ if (result)
+ {
+ m_dataCache.insert(paramname,result);
+ }
+ }
+
+ return result;
+ }
+
+ virtual void ClearCache()
+ {
+ FreeCacheObjects();
+ m_dataCache.clear();
+ }
+};
+
+#endif //__GEN_DATACACHE_H
+
diff --git a/source/kernel/gen_system/GEN_HashedPtr.cpp b/source/kernel/gen_system/GEN_HashedPtr.cpp
new file mode 100644
index 00000000000..4da40e6696d
--- /dev/null
+++ b/source/kernel/gen_system/GEN_HashedPtr.cpp
@@ -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 *****
+ *
+ */
+#include "GEN_HashedPtr.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//
+// Build hash index from pointer. Even though the final result
+// is a 32-bit integer, use all the bits of the pointer as long
+// as possible.
+//
+
+unsigned int GEN_Hash(void * inDWord)
+{
+#if defined(_WIN64)
+ unsigned __int64 key = (unsigned __int64)inDWord;
+#else
+ unsigned long key = (unsigned long)inDWord;
+#endif
+
+ key += ~(key << 16);
+ key ^= (key >> 5);
+ key += (key << 3);
+ key ^= (key >> 13);
+ key += ~(key << 9);
+ key ^= (key >> 17);
+
+ return (unsigned int)(key & 0xffffffff);
+}
diff --git a/source/kernel/gen_system/GEN_HashedPtr.h b/source/kernel/gen_system/GEN_HashedPtr.h
new file mode 100644
index 00000000000..51a89905409
--- /dev/null
+++ b/source/kernel/gen_system/GEN_HashedPtr.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 *****
+ *
+ */
+#ifndef __GEN_HASHEDPTR
+#define __GEN_HASHEDPTR
+
+unsigned int GEN_Hash(void * inDWord);
+
+class GEN_HashedPtr
+{
+ void* m_valptr;
+public:
+ GEN_HashedPtr(void* val) : m_valptr(val) {};
+ unsigned int hash() const { return GEN_Hash(m_valptr);};
+ inline friend bool operator ==(const GEN_HashedPtr & rhs, const GEN_HashedPtr & lhs) { return rhs.m_valptr == lhs.m_valptr;};
+};
+
+#endif //__GEN_HASHEDPTR
+
diff --git a/source/kernel/gen_system/GEN_Map.h b/source/kernel/gen_system/GEN_Map.h
new file mode 100644
index 00000000000..f6823252fb1
--- /dev/null
+++ b/source/kernel/gen_system/GEN_Map.h
@@ -0,0 +1,150 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by 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 GEN_MAP_H
+#define GEN_MAP_H
+
+template <class Key, class Value>
+class GEN_Map {
+private:
+ struct Entry {
+ Entry (Entry *next, Key key, Value value) :
+ m_next(next),
+ m_key(key),
+ m_value(value) {}
+
+ Entry *m_next;
+ Key m_key;
+ Value m_value;
+ };
+
+public:
+ GEN_Map(int num_buckets = 100) : m_num_buckets(num_buckets) {
+ m_buckets = new Entry *[num_buckets];
+ for (int i = 0; i < num_buckets; ++i) {
+ m_buckets[i] = 0;
+ }
+ }
+
+ int size() {
+ int count=0;
+ for (int i=0;i<m_num_buckets;i++)
+ {
+ Entry* bucket = m_buckets[i];
+ while(bucket)
+ {
+ bucket = bucket->m_next;
+ count++;
+ }
+ }
+ return count;
+ }
+
+ Value* at(int index) {
+ int count=0;
+ for (int i=0;i<m_num_buckets;i++)
+ {
+ Entry* bucket = m_buckets[i];
+ while(bucket)
+ {
+ if (count==index)
+ {
+ return &bucket->m_value;
+ }
+ bucket = bucket->m_next;
+ count++;
+ }
+ }
+ return 0;
+ }
+
+ void clear() {
+ for (int i = 0; i < m_num_buckets; ++i) {
+ Entry *entry_ptr = m_buckets[i];
+
+ while (entry_ptr != 0) {
+ Entry *tmp_ptr = entry_ptr->m_next;
+ delete entry_ptr;
+ entry_ptr = tmp_ptr;
+ }
+ m_buckets[i] = 0;
+ }
+ }
+
+ ~GEN_Map() {
+ clear();
+ delete [] m_buckets;
+ }
+
+ void insert(const Key& key, const Value& value) {
+ Entry *entry_ptr = m_buckets[key.hash() % m_num_buckets];
+ while ((entry_ptr != 0) && !(key == entry_ptr->m_key)) {
+ entry_ptr = entry_ptr->m_next;
+ }
+
+ if (entry_ptr != 0) {
+ entry_ptr->m_value = value;
+ }
+ else {
+ Entry **bucket = &m_buckets[key.hash() % m_num_buckets];
+ *bucket = new Entry(*bucket, key, value);
+ }
+ }
+
+ void remove(const Key& key) {
+ Entry **entry_ptr = &m_buckets[key.hash() % m_num_buckets];
+ while ((*entry_ptr != 0) && !(key == (*entry_ptr)->m_key)) {
+ entry_ptr = &(*entry_ptr)->m_next;
+ }
+
+ if (*entry_ptr != 0) {
+ Entry *tmp_ptr = (*entry_ptr)->m_next;
+ delete *entry_ptr;
+ *entry_ptr = tmp_ptr;
+ }
+ }
+
+ Value *operator[](Key key) {
+ Entry *bucket = m_buckets[key.hash() % m_num_buckets];
+ while ((bucket != 0) && !(key == bucket->m_key)) {
+ bucket = bucket->m_next;
+ }
+ return bucket != 0 ? &bucket->m_value : 0;
+ }
+
+private:
+ int m_num_buckets;
+ Entry **m_buckets;
+};
+
+#endif
+
+
diff --git a/source/kernel/gen_system/GEN_Matrix4x4.cpp b/source/kernel/gen_system/GEN_Matrix4x4.cpp
new file mode 100644
index 00000000000..4b941648e49
--- /dev/null
+++ b/source/kernel/gen_system/GEN_Matrix4x4.cpp
@@ -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 *****
+ */
+
+#include "GEN_Matrix4x4.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+GEN_Matrix4x4::GEN_Matrix4x4()
+{
+ Identity();
+}
+
+
+
+GEN_Matrix4x4::GEN_Matrix4x4(const float value[4][4])
+{
+ for (int i=0;i<4;i++)
+ {
+ for (int j=0;j<4;j++)
+ m_V[i][j] = value[i][j];
+ }
+}
+
+
+
+GEN_Matrix4x4::GEN_Matrix4x4(const double value[16])
+{
+ for (int i=0;i<16;i++)
+ m_Vflat[i] = value[i];
+}
+
+
+
+GEN_Matrix4x4::GEN_Matrix4x4(const GEN_Matrix4x4& other)
+{
+ SetMatrix(other);
+}
+
+
+
+GEN_Matrix4x4::GEN_Matrix4x4(const MT_Point3& orig,
+ const MT_Vector3& dir,
+ const MT_Vector3 up)
+{
+ MT_Vector3 z = -(dir.normalized());
+ MT_Vector3 x = (up.cross(z)).normalized();
+ MT_Vector3 y = (z.cross(x));
+
+ m_V[0][0] = x.x();
+ m_V[0][1] = y.x();
+ m_V[0][2] = z.x();
+ m_V[0][3] = 0.0f;
+
+ m_V[1][0] = x.y();
+ m_V[1][1] = y.y();
+ m_V[1][2] = z.y();
+ m_V[1][3] = 0.0f;
+
+ m_V[2][0] = x.z();
+ m_V[2][1] = y.z();
+ m_V[2][2] = z.z();
+ m_V[2][3] = 0.0f;
+
+ m_V[3][0] = orig.x();//0.0f;
+ m_V[3][1] = orig.y();//0.0f;
+ m_V[3][2] = orig.z();//0.0f;
+ m_V[3][3] = 1.0f;
+
+ //Translate(-orig);
+}
+
+
+
+MT_Vector3 GEN_Matrix4x4::GetRight() const
+{
+ return MT_Vector3(m_V[0][0], m_V[0][1], m_V[0][2]);
+}
+
+
+
+MT_Vector3 GEN_Matrix4x4::GetUp() const
+{
+ return MT_Vector3(m_V[1][0], m_V[1][1], m_V[1][2]);
+}
+
+
+
+MT_Vector3 GEN_Matrix4x4::GetDir() const
+{
+ return MT_Vector3(m_V[2][0], m_V[2][1], m_V[2][2]);
+}
+
+
+
+MT_Point3 GEN_Matrix4x4::GetPos() const
+{
+ return MT_Point3(m_V[3][0], m_V[3][1], m_V[3][2]);
+}
+
+
+
+void GEN_Matrix4x4::Identity()
+{
+ for (int i=0; i<4; i++)
+ {
+ for (int j=0; j<4; j++)
+ m_V[i][j] = (i==j?1.0f:0.0f);
+ }
+}
+
+
+
+void GEN_Matrix4x4::SetMatrix(const GEN_Matrix4x4& other)
+{
+ for (int i=0; i<16; i++)
+ m_Vflat[i] = other.m_Vflat[i];
+}
+
+
+
+double* GEN_Matrix4x4::getPointer()
+{
+ return &m_V[0][0];
+}
+
+
+
+const double* GEN_Matrix4x4::getPointer() const
+{
+ return &m_V[0][0];
+}
+
+
+
+void GEN_Matrix4x4::setElem(int pos,double newvalue)
+{
+ m_Vflat[pos] = newvalue;
+}
+
+
+
+
+
+GEN_Matrix4x4 GEN_Matrix4x4::Perspective(MT_Scalar inLeft,
+MT_Scalar inRight,
+MT_Scalar inBottom,
+MT_Scalar inTop,
+MT_Scalar inNear,
+MT_Scalar inFar)
+{
+
+ GEN_Matrix4x4 mat;
+
+ // Column 0
+ mat(0, 0) = -(2.0*inNear) / (inRight-inLeft);
+ mat(1, 0) = 0;
+ mat(2, 0) = 0;
+ mat(3, 0) = 0;
+
+ // Column 1
+ mat(0, 1) = 0;
+ mat(1, 1) = (2.0*inNear) / (inTop-inBottom);
+ mat(2, 1) = 0;
+ mat(3, 1) = 0;
+
+ // Column 2
+ mat(0, 2) = (inRight+inLeft) / (inRight-inLeft);
+ mat(1, 2) = (inTop+inBottom) / (inTop-inBottom);
+ mat(2, 2) = -(inFar+inNear) / (inFar-inNear);
+ mat(3, 2) = -1;
+
+ // Column 3
+ mat(0, 3) = 0;
+ mat(1, 3) = 0;
+ mat(2, 3) = -(2.0*inFar*inNear) / (inFar-inNear);
+ mat(3, 3) = 0;
+
+ return mat;
+}
diff --git a/source/kernel/gen_system/GEN_Matrix4x4.h b/source/kernel/gen_system/GEN_Matrix4x4.h
new file mode 100644
index 00000000000..8fc1539f777
--- /dev/null
+++ b/source/kernel/gen_system/GEN_Matrix4x4.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 GEN_MATRIX4X4
+#define GEN_MATRIX4X4
+
+#include "MT_Point3.h"
+
+class GEN_Matrix4x4
+{
+public:
+ // creators.
+ GEN_Matrix4x4();
+ GEN_Matrix4x4(const float value[4][4]);
+ GEN_Matrix4x4(const double value[16]);
+ GEN_Matrix4x4(const GEN_Matrix4x4 & other);
+ GEN_Matrix4x4(const MT_Point3& orig,
+ const MT_Vector3& dir,
+ const MT_Vector3 up);
+
+ void Identity();
+ void SetMatrix(const GEN_Matrix4x4 & other);
+ double* getPointer();
+ const double* getPointer() const;
+ void setElem(int pos,double newvalue);
+
+
+ MT_Vector3 GetRight() const;
+ MT_Vector3 GetUp() const;
+ MT_Vector3 GetDir() const;
+ MT_Point3 GetPos() const;
+ void SetPos(const MT_Vector3 & v);
+
+ double& operator () (int row,int col) { return m_V[col][row]; }
+
+ static GEN_Matrix4x4 Perspective(MT_Scalar inLeft,
+ MT_Scalar inRight,
+ MT_Scalar inBottom,
+ MT_Scalar inTop,
+ MT_Scalar inNear,
+ MT_Scalar inFar);
+protected:
+ union
+ {
+ double m_V[4][4];
+ double m_Vflat[16];
+ };
+};
+
+#endif //GEN_MATRIX4X4
+
diff --git a/source/kernel/gen_system/GEN_SmartPtr.h b/source/kernel/gen_system/GEN_SmartPtr.h
new file mode 100644
index 00000000000..88dc93528f2
--- /dev/null
+++ b/source/kernel/gen_system/GEN_SmartPtr.h
@@ -0,0 +1,236 @@
+#ifndef NAN_INCLUDED_GEN_SmartPtr_h
+#define NAN_INCLUDED_GEN_SmartPtr_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 *****
+ *
+ * @author Laurence
+ */
+
+#include <stdlib.h> // for NULL !
+
+/**
+ * @section GEN_SmartPtr
+ * This class defines a smart pointer similar to that defined in
+ * the Standard Template Library but without the painful get()
+ * semantics to access the internal c style pointer.
+ *
+ * It is often useful to explicitely decalre ownership of memory
+ * allocated on the heap within class or function scope. This
+ * class helps you to encapsulate this ownership within a value
+ * type. When an instance of this class goes out of scope it
+ * makes sure that any memory associated with it's internal pointer
+ * is deleted. It can help to inform users of an aggregate class
+ * that it owns instances of it's members and these instances
+ * should not be shared. This is not reliably enforcable in C++
+ * but this class attempts to make the 1-1 relationship clear.
+ *
+ * @section Example usage
+ *
+ * class foo {
+ * ...constructors accessors etc.
+ * int x[1000];
+ * }
+ *
+ * class bar {
+ * public :
+ * static
+ * bar *
+ * New(
+ * ) {
+ * GEN_SmartPtr<foo> afoo = new foo();
+ * GEN_SmartPtr<bar> that = new bar();
+ *
+ * if (foo == NULL || that == NULL) return NULL;
+ *
+ * that->m_foo = afoo.Release();
+ * return that.Release();
+ * }
+ *
+ * ~bar() {
+ * // smart ptr takes care of deletion
+ * }
+ * private :
+ * GEN_SmartPtr<foo> m_foo;
+ * }
+ *
+ * You my also safely construct vectors of GEN_SmartPtrs and
+ * have the vector own stuff you put into it.
+ *
+ * e.g.
+ * {
+ * std::vector<GEN_SmartPtr<foo> > foo_vector;
+ * foo_vector.push_back( new foo());
+ * foo_vector.push_back( new foo());
+ *
+ * foo_vector[0]->bla();
+ * } // foo_vector out of scope => heap memory freed for both foos
+ *
+ * @warning this class should only be used for objects created
+ * on the heap via the new function. It will not behave correctly
+ * if you pass ptrs to objects created with new[] nor with
+ * objects declared on the stack. Doing this is likely to crash
+ * the program or lead to memory leaks.
+ */
+
+template
+ < class T >
+class GEN_SmartPtr {
+
+public :
+
+ /**
+ * Construction from reference - this class
+ * always assumes ownership from the rhs.
+ */
+
+ GEN_SmartPtr(
+ const GEN_SmartPtr &rhs
+ ){
+ m_val = rhs.Release();
+ }
+
+ /**
+ * Construction from ptr - this class always
+ * assumes that it now owns the memory associated with the
+ * ptr.
+ */
+
+ GEN_SmartPtr(
+ T* val
+ ) :
+ m_val (val)
+ {
+ }
+
+ /**
+ * Defalut constructor
+ */
+
+ GEN_SmartPtr(
+ ) :
+ m_val (NULL)
+ {
+ }
+
+ /**
+ * Type conversion from this class to the type
+ * of a pointer to the template parameter.
+ * This means you can pass an instance of this class
+ * to a function expecting a ptr of type T.
+ */
+
+ operator T * () const {
+ return m_val;
+ }
+
+ /**
+ * Return a reference to the internal ptr class.
+ * Use with care when you now that the internal ptr
+ * is not NULL!
+ */
+
+ T &
+ Ref(
+ ) const {
+ return *m_val;
+ }
+
+ /**
+ * Assignment operator - ownership is transfered from rhs to lhs.
+ * There is an intenional side-effect of function of transferring
+ * ownership from the const parameter rhs. This is to insure
+ * the 1-1 relationship.
+ * The object associated with this instance is deleted if it
+ * is not the same as that contained in the rhs.
+ */
+
+ GEN_SmartPtr & operator=(
+ const GEN_SmartPtr &rhs
+ ) {
+ if (this->m_val != rhs.m_val) {
+ delete this->m_val;
+ }
+
+ this->m_val = rhs.Release();
+ return *this;
+ }
+
+ /**
+ * Overload the operator -> so that it's possible to access
+ * all the normal methods of the internal ptr.
+ */
+
+ T * operator->() const {
+ return m_val;
+ }
+
+ /**
+ * Caller takes ownership of the object - the object will not
+ * be deleted when the ptr goes out of scope.
+ */
+
+ T *
+ Release(
+ ) const {
+ T* temp = m_val;
+ (const_cast<GEN_SmartPtr *>(this))->m_val = NULL;
+ return temp;
+ }
+
+ /**
+ * Force destruction of the internal object.
+ */
+
+ void
+ Delete(
+ ) {
+ delete (m_val);
+ m_val = NULL;
+ }
+
+ /**
+ * Destructor - deletes object if it exists
+ */
+
+ ~GEN_SmartPtr(
+ ) {
+ delete (m_val);
+ }
+
+private :
+
+ /// The ptr owned by this class.
+ T * m_val;
+};
+
+#endif
+
diff --git a/source/kernel/gen_system/Makefile b/source/kernel/gen_system/Makefile
new file mode 100644
index 00000000000..cdaf8e8e598
--- /dev/null
+++ b/source/kernel/gen_system/Makefile
@@ -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.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = gen_system
+DIR = $(OCGDIR)/kernel/$(LIBNAME)
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_2_CPP_WARNINGS)
+
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_STRING)/include
+
diff --git a/source/kernel/gen_system/SYS_SingletonSystem.cpp b/source/kernel/gen_system/SYS_SingletonSystem.cpp
new file mode 100644
index 00000000000..b65ba69ec42
--- /dev/null
+++ b/source/kernel/gen_system/SYS_SingletonSystem.cpp
@@ -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 *****
+ * Unique instance of system class for system specific information / access
+ * Used by SYS_System
+ */
+#include "SYS_SingletonSystem.h"
+#include "GEN_DataCache.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+SYS_SingletonSystem* SYS_SingletonSystem::_instance = 0;
+
+void SYS_SingletonSystem::Destruct()
+{
+ if (_instance) {
+ delete _instance;
+ _instance = NULL;
+ }
+}
+
+SYS_SingletonSystem *SYS_SingletonSystem::Instance()
+{
+ if (!_instance) {
+ _instance = new SYS_SingletonSystem();
+ }
+ return _instance;
+}
+
+int SYS_SingletonSystem::SYS_GetCommandLineInt(const char *paramname, int defaultvalue)
+{
+ int *result = m_int_commandlineparms[paramname];
+ if (result)
+ return *result;
+
+ return defaultvalue;
+}
+
+float SYS_SingletonSystem::SYS_GetCommandLineFloat(const char *paramname, float defaultvalue)
+{
+ float *result = m_float_commandlineparms[paramname];
+ if (result)
+ return *result;
+
+ return defaultvalue;
+}
+
+const char *SYS_SingletonSystem::SYS_GetCommandLineString(const char *paramname, const char *defaultvalue)
+{
+ STR_String *result = m_string_commandlineparms[paramname];
+ if (result)
+ return *result;
+
+ return defaultvalue;
+}
+
+void SYS_SingletonSystem::SYS_WriteCommandLineInt(const char *paramname, int value)
+{
+ m_int_commandlineparms.insert(paramname, value);
+}
+
+void SYS_SingletonSystem::SYS_WriteCommandLineFloat(const char *paramname, float value)
+{
+ m_float_commandlineparms.insert(paramname, value);
+}
+
+void SYS_SingletonSystem::SYS_WriteCommandLineString(const char *paramname, const char *value)
+{
+ m_string_commandlineparms.insert(paramname, value);
+}
+
+SYS_SingletonSystem::SYS_SingletonSystem() : m_soundfilecache(NULL)
+{
+}
diff --git a/source/kernel/gen_system/SYS_SingletonSystem.h b/source/kernel/gen_system/SYS_SingletonSystem.h
new file mode 100644
index 00000000000..2d0d7088b76
--- /dev/null
+++ b/source/kernel/gen_system/SYS_SingletonSystem.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 *****
+ * Unique instance of system class for system specific information / access
+ * Used by SYS_System
+ */
+#ifndef __SINGLETONSYSTEM_H
+#define __SINGLETONSYSTEM_H
+
+#include "GEN_Map.h"
+#include "STR_HashedString.h"
+#include "GEN_DataCache.h"
+
+class SYS_SingletonSystem
+{
+public:
+ static SYS_SingletonSystem* Instance();
+ static void Destruct();
+
+ int SYS_GetCommandLineInt(const char* paramname,int defaultvalue);
+ float SYS_GetCommandLineFloat(const char* paramname,float defaultvalue);
+ const char* SYS_GetCommandLineString(const char* paramname,const char* defaultvalue);
+
+ void SYS_WriteCommandLineInt(const char* paramname,int value);
+ void SYS_WriteCommandLineFloat(const char* paramname,float value);
+ void SYS_WriteCommandLineString(const char* paramname,const char* value);
+
+ SYS_SingletonSystem();
+
+private:
+ static SYS_SingletonSystem* _instance;
+ GEN_Map<STR_HashedString,int> m_int_commandlineparms;
+ GEN_Map<STR_HashedString,float> m_float_commandlineparms;
+ GEN_Map<STR_HashedString,STR_String> m_string_commandlineparms;
+ void* m_soundfilecache;
+};
+
+#endif //__SINGLETONSYSTEM_H
+
diff --git a/source/kernel/gen_system/SYS_System.cpp b/source/kernel/gen_system/SYS_System.cpp
new file mode 100644
index 00000000000..84cd61f0ba6
--- /dev/null
+++ b/source/kernel/gen_system/SYS_System.cpp
@@ -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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * System specific information / access.
+ * Interface to the commandline arguments
+ */
+#include "SYS_System.h"
+#include "SYS_SingletonSystem.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+SYS_SystemHandle SYS_GetSystem()
+{
+ return (SYS_SystemHandle) SYS_SingletonSystem::Instance();
+}
+
+void SYS_DeleteSystem(SYS_SystemHandle sys)
+{
+ if (sys) {
+ ((SYS_SingletonSystem *) sys)->Destruct();
+ }
+}
+
+int SYS_GetCommandLineInt(SYS_SystemHandle sys, const char *paramname, int defaultvalue)
+{
+ return ((SYS_SingletonSystem *) sys)->SYS_GetCommandLineInt(paramname, defaultvalue);
+}
+
+float SYS_GetCommandLineFloat(SYS_SystemHandle sys, const char *paramname, float defaultvalue)
+{
+ return ((SYS_SingletonSystem *) sys)->SYS_GetCommandLineFloat(paramname, defaultvalue);
+}
+
+const char *SYS_GetCommandLineString(SYS_SystemHandle sys, const char *paramname, const char *defaultvalue)
+{
+ return ((SYS_SingletonSystem *) sys)->SYS_GetCommandLineString(paramname, defaultvalue);
+}
+
+void SYS_WriteCommandLineInt(SYS_SystemHandle sys, const char *paramname, int value)
+{
+ ((SYS_SingletonSystem *) sys)->SYS_WriteCommandLineInt(paramname, value);
+}
+
+void SYS_WriteCommandLineFloat(SYS_SystemHandle sys, const char *paramname, float value)
+{
+ ((SYS_SingletonSystem *) sys)->SYS_WriteCommandLineFloat(paramname, value);
+}
+
+void SYS_WriteCommandLineString(SYS_SystemHandle sys, const char *paramname, const char *value)
+{
+ ((SYS_SingletonSystem *) sys)->SYS_WriteCommandLineString(paramname, value);
+}
diff --git a/source/kernel/gen_system/SYS_System.h b/source/kernel/gen_system/SYS_System.h
new file mode 100644
index 00000000000..4125b662d2b
--- /dev/null
+++ b/source/kernel/gen_system/SYS_System.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 *****
+ * System specific information / access.
+ * Interface to the commandline arguments
+ */
+
+#ifndef __SYSTEM_INCLUDE
+#define __SYSTEM_INCLUDE
+
+#define SYS_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
+
+SYS_DECLARE_HANDLE(SYS_SystemHandle);
+
+/**
+ System specific information / access.
+ For now, only used for commandline parameters.
+ One of the available implementations must be linked to the application
+ that uses this system routines.
+ Please note that this protocol/interface is just for testing,
+ it needs discussion in the development group for a more final version.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern SYS_SystemHandle SYS_GetSystem(void);
+extern void SYS_DeleteSystem(SYS_SystemHandle sys);
+
+extern int SYS_GetCommandLineInt(SYS_SystemHandle sys, const char *paramname, int defaultvalue);
+extern float SYS_GetCommandLineFloat(SYS_SystemHandle sys, const char *paramname, float defaultvalue);
+extern const char *SYS_GetCommandLineString(SYS_SystemHandle sys, const char *paramname, const char *defaultvalue);
+
+extern void SYS_WriteCommandLineInt(SYS_SystemHandle sys, const char *paramname, int value);
+extern void SYS_WriteCommandLineFloat(SYS_SystemHandle sys, const char *paramname, float value);
+extern void SYS_WriteCommandLineString(SYS_SystemHandle sys, const char *paramname, const char *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__SYSTEM_INCLUDE
+
diff --git a/source/nan_compile.mk b/source/nan_compile.mk
new file mode 100644
index 00000000000..ae2717e3b5c
--- /dev/null
+++ b/source/nan_compile.mk
@@ -0,0 +1,391 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Compile and archive
+
+include nan_definitions.mk
+
+CPPFLAGS ?= $(NAN_CPPFLAGS)
+
+# common parts ---------------------------------------------------
+
+# Uncomment next lines to enable integrated game engine
+ifneq ($(NAN_NO_KETSJI), true)
+ CFLAGS += -DGAMEBLENDER=1
+ CFLAGS += -DUSE_SUMO_SOLID
+ CCFLAGS += -DUSE_SUMO_SOLID
+ ifeq ($(NAN_USE_BULLET), true)
+ CFLAGS += -DUSE_BULLET
+ CCFLAGS += -DUSE_BULLET
+ endif
+else
+ CPPFLAGS += -DNO_KETSJI
+endif
+
+ifdef NAN_DEBUG
+ CFLAGS += $(NAN_DEBUG)
+ CCFLAGS += $(NAN_DEBUG)
+endif
+
+REL_CFLAGS += -DNDEBUG
+REL_CCFLAGS += -DNDEBUG
+DBG_CFLAGS += -g
+DBG_CCFLAGS += -g
+
+# OS dependent parts ---------------------------------------------------
+
+ifeq ($(OS),beos)
+ CC = gcc
+ CCC = g++
+ CFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+ CCFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+ REL_CFLAGS += -O2
+ REL_CCFLAGS += -O2
+ NAN_DEPEND = true
+ OPENGL_HEADERS = .
+ CPPFLAGS += -D__BeOS
+ AR = ar
+ ARFLAGS = ruv
+ ARFLAGSQUIET = ru
+endif
+
+ifeq ($(OS),darwin)
+ CC = gcc
+ CCC = g++
+ ifeq ($(CPU),powerpc)
+ CFLAGS += -pipe -fPIC -ffast-math -mcpu=7450 -mtune=G5 -funsigned-char -fno-strict-aliasing
+ CCFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+ else
+ CFLAGS += -pipe -fPIC -ffast-math -march=pentium-m -funsigned-char -fno-strict-aliasing
+ CCFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+ endif
+ REL_CFLAGS += -O2
+ REL_CCFLAGS += -O2
+ CPPFLAGS += -D_THREAD_SAFE
+ NAN_DEPEND = true
+ OPENGL_HEADERS = /System/Library/Frameworks/OpenGL.framework
+ AR = ar
+ ARFLAGS = ruv
+ RANLIB = ranlib
+ ARFLAGSQUIET = ru
+endif
+
+ifeq ($(OS),freebsd)
+ CC = gcc
+ CCC = g++
+ JAVAC = javac
+ JAVAH = javah
+ CFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+ CCFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+ REL_CFLAGS += -O2
+ REL_CCFLAGS += -O2
+ CPPFLAGS += -D_THREAD_SAFE
+ NAN_DEPEND = true
+ OPENGL_HEADERS = /usr/X11R6/include
+ JAVA_HEADERS = /usr/local/jdk1.3.1/include
+ JAVA_SYSTEM_HEADERS = /usr/local/jdk1.3.1/include/freebsd
+ AR = ar
+ ARFLAGS = ruv
+ ARFLAGSQUIET = ru
+endif
+
+ifeq ($(OS),irix)
+ CC = cc
+ CCC = CC
+ CFLAGS += -n32 -mips3 -Xcpluscomm
+ CCFLAGS += -n32 -mips3 -Xcpluscomm -LANG:std
+ifdef MIPS73_ISOHEADERS
+ CCFLAGS += -LANG:libc_in_namespace_std=off -I$(MIPS73_ISOHEADERS)
+else
+ CCFLAGS += -LANG:libc_in_namespace_std=off
+endif
+ REL_CFLAGS += -n32 -mips3 -O2 -OPT:Olimit=0
+ REL_CCFLAGS += -n32 -mips3 -O2 -OPT:Olimit=0
+ OPENGL_HEADERS = /usr/include
+ NAN_DEPEND = true
+ AR = CC
+ ARFLAGS = -ar -o
+ ARFLAGSQUIET = -ar -o
+endif
+
+ifeq ($(OS),linux)
+ CC = gcc
+ CCC = g++
+# CFLAGS += -pipe
+ CFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+ CCFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+# CCFLAGS += -pipe
+ REL_CFLAGS += -O2
+ REL_CCFLAGS += -O2
+ NAN_DEPEND = true
+ ifeq ($(CPU),alpha)
+ CFLAGS += -mieee
+ endif
+ OPENGL_HEADERS = /usr/X11R6/include
+ AR = ar
+ ARFLAGS = ruv
+ ARFLAGSQUIET = ru
+endif
+
+ifeq ($(OS),openbsd)
+ CC = gcc
+ CCC = g++
+ CFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+ CCFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+ REL_CFLAGS += -O2
+ REL_CCFLAGS += -O2
+ NAN_DEPEND = true
+ CPPFLAGS += -D__FreeBSD__
+ OPENGL_HEADERS = /usr/X11R6/include
+ AR = ar
+ ARFLAGS = ruv
+ ARFLAGSQUIET = ru
+endif
+
+ifeq ($(OS),solaris)
+ CC = gcc
+ CCC = g++
+# CC = cc
+# CCC = CC
+ JAVAC = javac
+ JAVAH = javah
+ CFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+ CCFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing
+# CFLAGS += "-fast -xdepend -xarch=v8plus -xO3 -xlibmil -KPIC -DPIC -xchar=unsigned"
+# CCFLAGS += "-fast -xdepend -xarch=v8plus -xO3 -xlibmil -xlibmopt -features=tmplife -norunpath -KPIC -DPIC -xchar=unsigned"
+ REL_CFLAGS += -O1
+ REL_CCFLAGS += -O1
+ NAN_DEPEND = true
+ ifeq ($(CPU),sparc)
+ OPENGL_HEADERS = /usr/openwin/share/include
+ CPPFLAGS += -DSUN_OGL_NO_VERTEX_MACROS
+ JAVA_HEADERS = /usr/java/include
+ JAVA_SYSTEM_HEADERS = /usr/java/include/solaris
+ else
+ OPENGL_HEADERS = /usr/local/include
+ endif
+ AR = ar
+ ARFLAGS = ruv
+ ARFLAGSQUIET = ru
+endif
+
+ifeq ($(OS),windows)
+ ifeq ($(FREE_WINDOWS),true)
+ CC = gcc
+ CCC = g++
+ CFLAGS += -pipe -mno-cygwin -mwindows -funsigned-char -fno-strict-aliasing
+ CCFLAGS += -pipe -mno-cygwin -mwindows -funsigned-char -fno-strict-aliasing
+ CPPFLAGS += -DFREE_WINDOWS
+ REL_CFLAGS += -O2
+ REL_CCFLAGS += -O2
+ NAN_DEPEND = true
+ #OPENGL_HEADERS = /usr/include/w32api
+ OPENGL_HEADERS = ./
+ AR = ar
+ ARFLAGS = ruv
+ ARFLAGSQUIET = ru
+ WINRC = $(wildcard *.rc)
+ RANLIB = ranlib
+ else
+ CC = $(SRCHOME)/tools/cygwin/cl_wrapper.pl
+ CCC = $(SRCHOME)/tools/cygwin/cl_wrapper.pl
+ JAVAC = $(SRCHOME)/tools/cygwin/java_wrapper.pl -c
+ JAVAH = $(SRCHOME)/tools/cygwin/java_wrapper.pl -h
+ REL_CFLAGS += /O2
+ REL_CCFLAGS += /O2 -GX
+ DBG_CFLAGS += /Fd$(DIR)/debug/
+ DBG_CCFLAGS += /Fd$(DIR)/debug/
+ CFLAGS += /MT
+ CCFLAGS += /MT
+ NAN_DEPEND = true
+ OPENGL_HEADERS = .
+ CPPFLAGS += -DWIN32 -D_WIN32 -D__WIN32
+ CPPFLAGS += -D_M_IX86
+ CPPFLAGS += -I"/cygdrive/c/Program Files/Microsoft Visual Studio/VC98/include"
+ JAVA_HEADERS = /cygdrive/c/j2sdk1.4.0-beta3/include
+ JAVA_SYSTEM_HEADERS = /cygdrive/c/j2sdk1.4.0-beta3/include/win32
+ CPP = $(SRCHOME)/tools/cygwin/cl_wrapper.pl
+ AR = ar
+ ARFLAGS = ruv
+ ARFLAGSQUIET = ru
+ WINRC = $(wildcard *.rc)
+ endif
+endif
+
+ifeq (debug, $(findstring debug, $(MAKECMDGOALS)))
+ export DEBUG_DIR=debug/
+endif
+
+ifneq (x$(DEBUG_DIR), x)
+ CFLAGS +=$(DBG_CFLAGS)
+ CCFLAGS+=$(DBG_CCFLAGS)
+else
+ CFLAGS +=$(REL_CFLAGS)
+ CCFLAGS+=$(REL_CCFLAGS)
+endif
+
+# Note: include nan_warn's LEVEL_*_WARNINGS after CC/OS have been set.
+include nan_warn.mk
+
+# compile rules
+
+default: all
+
+$(DIR)/$(DEBUG_DIR)%.o: %.c
+ ifdef NAN_DEPEND
+ @set -e; $(CC) -M $(CPPFLAGS) $< 2>/dev/null \
+ | sed 's@\($*\)\.o[ :]*@$(DIR)/$(DEBUG_DIR)\1.o : @g' \
+ > $(DIR)/$(DEBUG_DIR)$*.d; \
+ [ -s $(DIR)/$(DEBUG_DIR)$*.d ] || $(RM) $(DIR)/$(DEBUG_DIR)$*.d
+ endif
+ ifdef NAN_QUIET
+ @echo " -- $< -- "
+ @$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
+ else
+ $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
+ endif
+
+$(DIR)/$(DEBUG_DIR)%.o: %.cpp
+ ifdef NAN_DEPEND
+ @set -e; $(CCC) -M $(CPPFLAGS) $< 2>/dev/null \
+ | sed 's@\($*\)\.o[ :]*@$(DIR)/$(DEBUG_DIR)\1.o : @g' \
+ > $(DIR)/$(DEBUG_DIR)$*.d; \
+ [ -s $(DIR)/$(DEBUG_DIR)$*.d ] || $(RM) $(DIR)/$(DEBUG_DIR)$*.d
+ endif
+ ifdef NAN_QUIET
+ @echo " -- $< -- "
+ @$(CCC) -c $(CCFLAGS) $(CPPFLAGS) $< -o $@
+ else
+ $(CCC) -c $(CCFLAGS) $(CPPFLAGS) $< -o $@
+ endif
+
+$(DIR)/$(DEBUG_DIR)%.res: %.rc
+ifeq ($(FREE_WINDOWS),true)
+ windres $< -O coff -o $@
+else
+ $(SRCHOME)/tools/cygwin/cl_wrapper.pl - rc /fo$@ $<
+endif
+
+$(DIR)/$(DEBUG_DIR)%.class: %.java
+ ifdef JARS
+ $(JAVAC) -verbose -g -deprecation -sourcepath . -classpath "$(JARS)" -d $(DIR)/$(DEBUG_DIR) $<
+ else
+ $(JAVAC) -verbose -g -deprecation -d $(DIR)/$(DEBUG_DIR) $<
+ endif
+
+$(DIR)/$(DEBUG_DIR)%.h: $(DIR)/$(DEBUG_DIR)%.class
+ $(JAVAH) -classpath $(DIR)/$(DEBUG_DIR) -d $(DIR)/$(DEBUG_DIR) -jni $*
+
+%.h:
+ @echo "WARNING: Fake header creation rule used, dependencies will be remade"
+
+CSRCS ?= $(wildcard *.c)
+CCSRCS ?= $(wildcard *.cpp)
+JSRCS ?= $(wildcard *.java)
+
+ifdef NAN_DEPEND
+-include $(CSRCS:%.c=$(DIR)/$(DEBUG_DIR)%.d) $(CCSRCS:%.cpp=$(DIR)/$(DEBUG_DIR)%.d)
+endif
+
+OBJS_AR := $(OBJS)
+OBJS_AR += $(CSRCS:%.c=%.o)
+OBJS_AR += $(CCSRCS:%.cpp=%.o)
+OBJS_AR += $(WINRC:%.rc=%.res)
+
+OBJS += $(CSRCS:%.c=$(DIR)/$(DEBUG_DIR)%.o)
+OBJS += $(CCSRCS:%.cpp=$(DIR)/$(DEBUG_DIR)%.o)
+OBJS += $(WINRC:%.rc=$(DIR)/$(DEBUG_DIR)%.res)
+
+JCLASS += $(JSRCS:%.java=$(DIR)/$(DEBUG_DIR)%.class)
+
+LIB_a = $(DIR)/$(DEBUG_DIR)lib$(LIBNAME).a
+
+$(LIB_a): $(OBJS)
+ # $OBJS can be empty except for some spaces
+ ifneq (x, x$(strip $(OBJS)))
+ ifdef NAN_PARANOID
+ @$(RM) $(LIB_a)
+ ifdef NAN_QUIET
+ @echo " -- lib: lib$(LIBNAME).a -- "
+ @cd $(DIR)/$(DEBUG_DIR); $(AR) $(ARFLAGSQUIET) $@ $(OBJS_AR)
+ else
+ cd $(DIR)/$(DEBUG_DIR); $(AR) $(ARFLAGS) $@ $(OBJS_AR)
+ endif
+ else
+ ifdef NAN_QUIET
+ @echo " -- lib: lib$(LIBNAME).a -- "
+ @$(AR) $(ARFLAGSQUIET) $@ $?
+ else
+ $(AR) $(ARFLAGS) $@ $?
+ endif
+ endif
+ ifdef RANLIB
+ $(RANLIB) $@
+ endif
+ endif
+
+ALLTARGETS ?= $(LIB_a)
+
+all debug :: makedir $(ALLTARGETS)
+
+lib: $(LIB_a)
+
+creator: $(OBJS)
+ @echo "====> make creator subtarget in `pwd | sed 's/^.*develop\///'`"
+ @$(MAKE) makedir DIR=$(DIR)/$(DEBUG_DIR)cre
+ @$(MAKE) lib CSRCS="$(CRE_CSRCS)" LIBNAME=$(LIBNAME)$@
+
+publisher: $(OBJS)
+ @echo "====> make publisher subtarget in `pwd | sed 's/^.*develop\///'`"
+ @$(MAKE) makedir DIR=$(DIR)/$(DEBUG_DIR)pub
+ @$(MAKE) lib CSRCS="$(PUB_CSRCS)" LIBNAME=$(LIBNAME)$@
+
+player: $(OBJS)
+ @echo "====> make player subtarget in `pwd | sed 's/^.*develop\///'`"
+ @$(MAKE) makedir DIR=$(DIR)/player/$(DEBUG_DIR)
+ @$(MAKE) lib CSRCS="$(SAP_CSRCS)" LIBNAME=$(LIBNAME)$@
+
+clean:: optclean debugclean
+
+optclean::
+ @-[ ! -d $(DIR) ] || ( cd $(DIR) && \
+ $(RM) *.o *.a *.d *.res ii_files/*.ii *.class *.h )
+
+debugclean::
+ @-[ ! -d $(DIR)/debug ] || ( cd $(DIR)/debug && \
+ $(RM) *.o *.a *.d *.res ii_files/*.ii *.class *.h )
+
+.PHONY: makedir
+makedir::
+ @# don't use mkdir -p. Cygwin will try to make network paths and fail
+ @[ -d $(DIR) ] || mkdir $(DIR)
+ @[ -d $(DIR)/debug ] || mkdir $(DIR)/debug
+
diff --git a/source/nan_definitions.mk b/source/nan_definitions.mk
new file mode 100644
index 00000000000..7fa3eb98e00
--- /dev/null
+++ b/source/nan_definitions.mk
@@ -0,0 +1,603 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# set some defaults when these are not overruled (?=) by environment variables
+#
+
+sinclude ../user-def.mk
+
+ifndef CONFIG_GUESS
+ ifeq (debug, $(findstring debug, $(MAKECMDGOALS)))
+ ifeq (all, $(findstring all, $(MAKECMDGOALS)))
+all debug::
+ ERRTXT = "ERROR: all and debug targets cannot be used together anymore"
+ ERRTXT += "Use something like ..make all && make debug.. instead"
+ $(error $(ERRTXT))
+ endif
+ endif
+
+ # First generic defaults for all platforms which should be constant.
+ # Note: ?= lets these defaults be overruled by environment variables,
+ export SRCHOME ?= $(NANBLENDERHOME)/source
+ export CONFIG_GUESS := $(shell ${SRCHOME}/tools/guess/guessconfig)
+ export OS := $(shell echo ${CONFIG_GUESS} | sed -e 's/-.*//')
+ export OS_VERSION := $(shell echo ${CONFIG_GUESS} | sed -e 's/^[^-]*-//' -e 's/-[^-]*//')
+ export CPU := $(shell echo ${CONFIG_GUESS} | sed -e 's/^[^-]*-[^-]*-//')
+ export MAKE_START := $(shell date "+%H:%M:%S %d-%b-%Y")
+ export NAN_LIBDIR ?= $(NANBLENDERHOME)/../lib
+ export NAN_OBJDIR ?= $(NANBLENDERHOME)/obj
+ # Library Config_Guess DIRectory
+ export LCGDIR = $(NAN_LIBDIR)/$(CONFIG_GUESS)
+ # Object Config_Guess DIRectory
+ export OCGDIR = $(NAN_OBJDIR)/$(CONFIG_GUESS)
+
+ # Determines what targets are built
+ export WITH_BF_DYNAMICOPENGL ?= true
+ export WITH_BF_STATICOPENGL ?= false
+ export WITH_BF_BLENDERGAMEENGINE ?= true
+ export WITH_BF_BLENDERPLAYER ?= true
+ export WITH_BF_WEBPLUGIN ?= false
+
+ export NAN_MOTO ?= $(LCGDIR)/moto
+ifeq ($(FREE_WINDOWS), true)
+ export NAN_SOLID ?= $(LCGDIR)/gcc/solid
+ export NAN_QHULL ?= $(LCGDIR)/gcc/qhull
+else
+ export NAN_SOLID ?= $(LCGDIR)/solid
+ export NAN_QHULL ?= $(LCGDIR)/qhull
+endif
+ export NAN_BULLET2 ?= $(LCGDIR)/bullet2
+ export NAN_SUMO ?= $(SRCHOME)/gameengine/Physics/Sumo
+ export NAN_FUZZICS ?= $(SRCHOME)/gameengine/Physics/Sumo/Fuzzics
+ export NAN_BLENKEY ?= $(LCGDIR)/blenkey
+ export NAN_DECIMATION ?= $(LCGDIR)/decimation
+ export NAN_GUARDEDALLOC ?= $(LCGDIR)/guardedalloc
+ export NAN_IKSOLVER ?= $(LCGDIR)/iksolver
+ export NAN_BSP ?= $(LCGDIR)/bsp
+ export NAN_BOOLOP ?= $(LCGDIR)/boolop
+ export NAN_SOUNDSYSTEM ?= $(LCGDIR)/SoundSystem
+ export NAN_STRING ?= $(LCGDIR)/string
+ export NAN_MEMUTIL ?= $(LCGDIR)/memutil
+ export NAN_CONTAINER ?= $(LCGDIR)/container
+ export NAN_ACTION ?= $(LCGDIR)/action
+ export NAN_GHOST ?= $(LCGDIR)/ghost
+ export NAN_TEST_VERBOSITY ?= 1
+ export NAN_BMFONT ?= $(LCGDIR)/bmfont
+ export NAN_OPENNL ?= $(LCGDIR)/opennl
+ export NAN_ELBEEM ?= $(LCGDIR)/elbeem
+ export NAN_SUPERLU ?= $(LCGDIR)/superlu
+ ifeq ($(FREE_WINDOWS), true)
+ export NAN_FTGL ?= $(LCGDIR)/gcc/ftgl
+ export NAN_FFMPEG ?= $(LCGDIR)/gcc/ffmpeg
+ export NAN_FFMPEGLIBS ?= $(NAN_FFMPEG)/lib/libavformat.a $(NAN_FFMPEG)/lib/libavutil.a $(NAN_FFMPEG)/lib/libavcodec.a
+ export NAN_FFMPEGCFLAGS ?= -I$(NAN_FFMPEG)/include
+ else
+ export NAN_FTGL ?= $(LCGDIR)/ftgl
+ export NAN_FFMPEG ?= $(LCGDIR)/ffmpeg
+ export NAN_FFMPEGLIBS ?= $(NAN_FFMPEG)/lib/libavformat.a $(NAN_FFMPEG)/lib/libavcodec.a $(NAN_FFMPEG)/lib/libswscale.a $(NAN_FFMPEG)/lib/libavutil.a
+ export NAN_FFMPEGCFLAGS ?= -I$(NAN_FFMPEG)/include
+ endif
+
+ ifeq ($(WITH_VERSE), true)
+ export NAN_VERSE ?= $(LCGDIR)/verse
+ endif
+
+ export WITH_OPENEXR ?= true
+ export WITH_DDS ?= true
+
+ ifeq ($(OS),windows)
+ export NAN_WINTAB ?= $(LCGDIR)/wintab
+ ifeq ($(FREE_WINDOWS), true)
+ export NAN_PTHREADS ?= $(LCGDIR)/pthreads
+ export NAN_OPENEXR ?= $(LCGDIR)/gcc/openexr
+ export NAN_OPENEXR_LIBS ?= $(NAN_OPENEXR)/lib/libIlmImf.a $(NAN_OPENEXR)/lib/libHalf.a $(NAN_OPENEXR)/lib/libIex.a
+ export NAN_OPENEXR_INC ?= -I$(NAN_OPENEXR)/include -I$(NAN_OPENEXR)/include/OpenEXR
+ else
+ export NAN_OPENEXR ?= $(LCGDIR)/openexr
+ export NAN_OPENEXR_LIBS ?= $(NAN_OPENEXR)/lib/IlmImf.lib $(NAN_OPENEXR)/lib/Half.lib $(NAN_OPENEXR)/lib/Iex.lib
+ export NAN_OPENEXR_INC ?= -I$(NAN_OPENEXR)/include -I$(NAN_OPENEXR)/include/IlmImf -I$(NAN_OPENEXR)/include/Imath -I$(NAN_OPENEXR)/include/Iex
+ endif
+ else
+ ifeq ($(OS),darwin)
+ export NAN_OPENEXR ?= $(LCGDIR)/openexr
+ ifeq ($(CPU),powerpc)
+ export NAN_OPENEXR_LIBS ?= $(NAN_OPENEXR)/lib/libIlmImf.a $(NAN_OPENEXR)/lib/libHalf.a $(NAN_OPENEXR)/lib/libIex.a
+ else
+ export NAN_OPENEXR_LIBS ?= $(NAN_OPENEXR)/lib/libIlmImf.a $(NAN_OPENEXR)/lib/libHalf.a $(NAN_OPENEXR)/lib/libIex.a $(NAN_OPENEXR)/lib/libIlmThread.a
+ endif
+ else
+ ifeq ($(OS),linux)
+ ifeq ($(WITH_OPENEXR), true)
+ NAN_OPENEXR?=$(shell pkg-config --variable=prefix OpenEXR )
+ NAN_OPENEXR_INC?=$(shell pkg-config --cflags OpenEXR )
+ NAN_OPENEXR_LIBS?=$(addprefix ${NAN_OPENEXR}/lib/lib,$(addsuffix .a,$(shell pkg-config --libs OpenEXR | sed -s "s/-l//g" )))
+ endif
+ else
+ export NAN_OPENEXR ?= /usr/local
+ export NAN_OPENEXR_LIBS ?= $(NAN_OPENEXR)/lib/libIlmImf.a $(NAN_OPENEXR)/lib/libHalf.a $(NAN_OPENEXR)/lib/libIex.a
+ endif
+ endif
+ ifeq ($(WITH_OPENEXR), true)
+ export NAN_OPENEXR_INC ?= -I$(NAN_OPENEXR)/include -I$(NAN_OPENEXR)/include/OpenEXR
+ endif
+
+ endif
+ # Platform Dependent settings go below:
+
+ ifeq ($(NAN_USE_FFMPEG_CONFIG), true)
+ export NAN_FFMPEG ?= $(shell ffmpeg-config --prefix)
+ export NAN_FFMPEGLIBS ?= $(shell ffmpeg-config --libs avformat avcodec)
+ export NAN_FFMPEGCFLAGS ?= $(shell ffmpeg-config --cflags)
+ endif
+
+ ifeq ($(OS),beos)
+
+ export ID = $(USER)
+ export HOST = $(HOSTNAME)
+ export NAN_PYTHON ?= $(LCGDIR)/python
+ export NAN_PYTHON_VERSION ?= 2.3
+ export NAN_PYTHON_BINARY ?= $(NAN_PYTHON)/bin/python$(NAN_PYTHON_VERSION)
+ export NAN_OPENAL ?= $(LCGDIR)/openal
+ export NAN_FMOD ?= $(LCGDIR)/fmod
+ export NAN_JPEG ?= $(LCGDIR)/jpeg
+ export NAN_PNG ?= $(LCGDIR)/png
+ export NAN_TIFF ?= $(LCGDIR)/tiff
+ export NAN_ODE ?= $(LCGDIR)/ode
+ export NAN_TERRAPLAY ?= $(LCGDIR)/terraplay
+ export NAN_MESA ?= /usr/src/Mesa-3.1
+ export NAN_ZLIB ?= $(LCGDIR)/zlib
+ export NAN_NSPR ?= $(LCGDIR)/nspr
+ export NAN_FREETYPE ?= $(LCGDIR)/freetype
+ export NAN_GETTEXT ?= $(LCGDIR)/gettext
+ export NAN_SDL ?= $(shell sdl-config --prefix)
+ export NAN_SDLLIBS ?= $(shell sdl-config --libs)
+ export NAN_SDLCFLAGS ?= $(shell sdl-config --cflags)
+
+ # Uncomment the following line to use Mozilla inplace of netscape
+ # CPPFLAGS +=-DMOZ_NOT_NET
+ # Location of MOZILLA/Netscape header files...
+ export NAN_MOZILLA_INC ?= $(LCGDIR)/mozilla/include
+ export NAN_MOZILLA_LIB ?= $(LCGDIR)/mozilla/lib/
+ # Will fall back to look in NAN_MOZILLA_INC/nspr and NAN_MOZILLA_LIB
+ # if this is not set.
+
+ export NAN_BUILDINFO ?= true
+ # Be paranoid regarding library creation (do not update archives)
+ export NAN_PARANOID ?= true
+
+ # l10n
+ #export INTERNATIONAL ?= true
+
+ # enable freetype2 support for text objects
+ #export WITH_FREETYPE2 ?= true
+
+ else
+ ifeq ($(OS),darwin)
+
+ export ID = $(shell whoami)
+ export HOST = $(shell hostname -s)
+
+ export PY_FRAMEWORK = 1
+
+ ifdef PY_FRAMEWORK
+ export NAN_PYTHON ?= /System/Library/Frameworks/Python.framework/Versions/2.3
+ export NAN_PYTHON_VERSION ?= 2.3
+ export NAN_PYTHON_BINARY ?= $(NAN_PYTHON)/bin/python$(NAN_PYTHON_VERSION)
+ else
+ export NAN_PYTHON ?= /sw
+ export NAN_PYTHON_VERSION ?= 2.3
+ export NAN_PYTHON_BINARY ?= $(NAN_PYTHON)/bin/python$(NAN_PYTHON_VERSION)
+ endif
+
+ export NAN_OPENAL ?= $(LCGDIR)/openal
+ export NAN_FMOD ?= $(LCGDIR)/fmod
+ export NAN_JPEG ?= $(LCGDIR)/jpeg
+ export NAN_PNG ?= $(LCGDIR)/png
+ export NAN_TIFF ?= $(LCGDIR)/tiff
+ export NAN_ODE ?= $(LCGDIR)/ode
+ export NAN_TERRAPLAY ?= $(LCGDIR)/terraplay
+ export NAN_MESA ?= /usr/src/Mesa-3.1
+ export NAN_ZLIB ?= $(LCGDIR)/zlib
+ export NAN_NSPR ?= $(LCGDIR)/nspr
+ export NAN_FREETYPE ?= $(LCGDIR)/freetype
+ export NAN_GETTEXT ?= $(LCGDIR)/gettext
+ export NAN_SDL ?= $(LCGDIR)/sdl
+ export NAN_SDLCFLAGS ?= -I$(NAN_SDL)/include
+ export NAN_SDLLIBS ?= $(NAN_SDL)/lib/libSDL.a -framework Cocoa -framework IOKit
+
+ # export NAN_NO_KETSJI=true
+
+ ifeq ($(CPU), i386)
+ export NAN_NO_OPENAL=true
+ endif
+
+ # Uncomment the following line to use Mozilla inplace of netscape
+ # CPPFLAGS +=-DMOZ_NOT_NET
+ # Location of MOZILLA/Netscape header files...
+ export NAN_MOZILLA_INC ?= $(LCGDIR)/mozilla/include
+ export NAN_MOZILLA_LIB ?= $(LCGDIR)/mozilla/lib/
+ # Will fall back to look in NAN_MOZILLA_INC/nspr and NAN_MOZILLA_LIB
+ # if this is not set.
+
+ export NAN_BUILDINFO ?= true
+ # Be paranoid regarding library creation (do not update archives)
+ export NAN_PARANOID ?= true
+
+ # enable quicktime by default on OS X
+ export WITH_QUICKTIME ?= true
+
+ # enable l10n
+ export INTERNATIONAL ?= true
+
+ # enable freetype2 support for text objects
+ export WITH_FREETYPE2 ?= true
+
+ else
+ ifeq ($(OS),freebsd)
+
+ export ID = $(shell whoami)
+ export HOST = $(shell hostname -s)
+ export FREEDESKTOP ?= true
+
+ export NAN_PYTHON ?= /usr/local
+ export NAN_PYTHON_VERSION ?= 2.3
+ export NAN_PYTHON_BINARY ?= $(NAN_PYTHON)/bin/python$(NAN_PYTHON_VERSION)
+ export NAN_OPENAL ?= /usr/local
+ export NAN_FMOD ?= $(LCGDIR)/fmod
+ export NAN_JPEG ?= /usr/local
+ export NAN_PNG ?= /usr/local
+ export NAN_TIFF ?= /usr/local
+ export NAN_ODE ?= $(LCGDIR)/ode
+ export NAN_TERRAPLAY ?= $(LCGDIR)/terraplay
+ export NAN_MESA ?= /usr/src/Mesa-3.1
+ export NAN_ZLIB ?= /usr
+ export NAN_NSPR ?= /usr/local
+ export NAN_FREETYPE ?= $(LCGDIR)/freetype
+ export NAN_GETTEXT ?= $(LCGDIR)/gettext
+ export NAN_SDL ?= $(shell sdl11-config --prefix)
+ export NAN_SDLLIBS ?= $(shell sdl11-config --libs)
+ export NAN_SDLCFLAGS ?= $(shell sdl11-config --cflags)
+
+ # Uncomment the following line to use Mozilla inplace of netscape
+ # CPPFLAGS +=-DMOZ_NOT_NET
+ # Location of MOZILLA/Netscape header files...
+ export NAN_MOZILLA_INC ?= $(LCGDIR)/mozilla/include
+ export NAN_MOZILLA_LIB ?= $(LCGDIR)/mozilla/lib/
+ # Will fall back to look in NAN_MOZILLA_INC/nspr and NAN_MOZILLA_LIB
+ # if this is not set.
+
+ export NAN_BUILDINFO ?= true
+ # Be paranoid regarding library creation (do not update archives)
+ export NAN_PARANOID ?= true
+
+ # enable l10n
+ # export INTERNATIONAL ?= true
+
+ # enable freetype2 support for text objects
+ # export WITH_FREETYPE2 ?= true
+
+ else
+ ifeq ($(OS),irix)
+
+ export ID = $(shell whoami)
+ export HOST = $(shell /usr/bsd/hostname -s)
+ #export NAN_NO_KETSJI=true
+ export NAN_JUST_BLENDERDYNAMIC=true
+ export NAN_PYTHON ?= $(LCGDIR)/python
+ export NAN_PYTHON_VERSION ?= 2.3
+ export NAN_PYTHON_BINARY ?= $(NAN_PYTHON)/bin/python$(NAN_PYTHON_VERSION)
+ export NAN_OPENAL ?= $(LCGDIR)/openal
+ export NAN_FMOD ?= $(LCGDIR)/fmod
+ export NAN_JPEG ?= $(LCGDIR)/jpeg
+ export NAN_PNG ?= $(LCGDIR)/png
+ export NAN_TIFF ?= /usr/freeware
+ export NAN_ODE ?= $(LCGDIR)/ode
+ export NAN_TERRAPLAY ?= $(LCGDIR)/terraplay
+ export NAN_MESA ?= /usr/src/Mesa-3.1
+ export NAN_ZLIB ?= /usr/freeware
+ export NAN_NSPR ?= $(LCGDIR)/nspr
+ export NAN_FREETYPE ?= /usr/freeware
+ export NAN_GETTEXT ?= /usr/freeware
+ export NAN_SDL ?= $(LCGDIR)/sdl
+ export NAN_SDLLIBS ?= -L$(NAN_SDL)/lib -lSDL
+ export NAN_SDLCFLAGS ?= -I$(NAN_SDL)/include/SDL
+
+ # Uncomment the following line to use Mozilla inplace of netscape
+ # CPPFLAGS +=-DMOZ_NOT_NET
+ # Location of MOZILLA/Netscape header files...
+ export NAN_MOZILLA_INC ?= $(LCGDIR)/mozilla/include
+ export NAN_MOZILLA_LIB ?= $(LCGDIR)/mozilla/lib/
+ # Will fall back to look in NAN_MOZILLA_INC/nspr and NAN_MOZILLA_LIB
+ # if this is not set.
+
+ export NAN_BUILDINFO ?= true
+ # Be paranoid regarding library creation (do not update archives)
+ export NAN_PARANOID ?= true
+
+ # enable l10n
+ export INTERNATIONAL ?= true
+
+ # enable freetype2 support for text objects
+ export WITH_FREETYPE2 ?= true
+
+ else
+ ifeq ($(OS),linux)
+
+ export ID = $(shell whoami)
+ export HOST = $(shell hostname -s)
+ export FREEDESKTOP ?= true
+
+ export NAN_PYTHON ?= /usr
+ export NAN_PYTHON_VERSION ?= 2.5
+ export NAN_PYTHON_BINARY ?= $(NAN_PYTHON)/bin/python$(NAN_PYTHON_VERSION)
+ export NAN_OPENAL ?= /usr
+ export NAN_FMOD ?= $(LCGDIR)/fmod
+ export NAN_JPEG ?= /usr
+ export NAN_PNG ?= /usr
+ export NAN_TIFF ?= /usr
+ export NAN_ODE ?= $(LCGDIR)/ode
+ export NAN_TERRAPLAY ?= $(LCGDIR)/terraplay
+ export NAN_MESA ?= /usr
+ export NAN_ZLIB ?= /usr
+ export NAN_NSPR ?= $(LCGDIR)/nspr
+ export NAN_FREETYPE ?= /usr
+ export NAN_GETTEXT ?= /usr
+ export NAN_SDL ?= $(shell sdl-config --prefix)
+ export NAN_SDLLIBS ?= $(shell sdl-config --libs)
+ export NAN_SDLCFLAGS ?= $(shell sdl-config --cflags)
+
+ifneq ($(NAN_USE_FFMPEG_CONFIG), true)
+ export NAN_FFMPEG ?= /usr
+ export NAN_FFMPEGLIBS ?= -L$(NAN_FFMPEG)/lib -lavformat -lavcodec -lavutil -lswscale -ldts -lz
+ export NAN_FFMPEGCFLAGS ?= -I$(NAN_FFMPEG)/include
+endif
+
+ # Uncomment the following line to use Mozilla inplace of netscape
+ export CPPFLAGS += -DMOZ_NOT_NET
+ # Location of MOZILLA/Netscape header files...
+ export NAN_MOZILLA_INC ?= /usr/include/mozilla
+ export NAN_MOZILLA_LIB ?= $(LCGDIR)/mozilla/lib/
+ # Will fall back to look in NAN_MOZILLA_INC/nspr and NAN_MOZILLA_LIB
+ # if this is not set.
+
+ export NAN_BUILDINFO ?= true
+ # Be paranoid regarding library creation (do not update archives)
+ export NAN_PARANOID ?= true
+
+ # l10n
+ export INTERNATIONAL ?= true
+
+ # enable freetype2 support for text objects
+ export WITH_FREETYPE2 ?= true
+
+ # enable ffmpeg support
+ ifndef NAN_NO_FFMPEG
+ export WITH_FFMPEG ?= true
+ endif
+
+ else
+ ifeq ($(OS),openbsd)
+
+ export ID = $(shell whoami)
+ export HOST = $(shell hostname -s)
+ export FREEDESKTOP ?= true
+
+ export NAN_PYTHON ?= $(LCGDIR)/python
+ export NAN_PYTHON_VERSION ?= 2.3
+ export NAN_PYTHON_BINARY ?= $(NAN_PYTHON)/bin/python$(NAN_PYTHON_VERSION)
+ export NAN_OPENAL ?= $(LCGDIR)/openal
+ export NAN_FMOD ?= $(LCGDIR)/fmod
+ export NAN_JPEG ?= $(LCGDIR)/jpeg
+ export NAN_PNG ?= $(LCGDIR)/png
+ export NAN_TIFF ?= $(LCGDIR)/tiff
+ export NAN_ODE ?= $(LCGDIR)/ode
+ export NAN_TERRAPLAY ?= $(LCGDIR)/terraplay
+ export NAN_MESA ?= /usr/src/Mesa-3.1
+ export NAN_ZLIB ?= $(LCGDIR)/zlib
+ export NAN_NSPR ?= $(LCGDIR)/nspr
+ export NAN_FREETYPE ?= $(LCGDIR)/freetype
+ export NAN_GETTEXT ?= $(LCGDIR)/gettext
+ export NAN_SDL ?= $(shell sdl-config --prefix)
+ export NAN_SDLLIBS ?= $(shell sdl-config --libs)
+ export NAN_SDLCFLAGS ?= $(shell sdl-config --cflags)
+
+ # Uncomment the following line to use Mozilla inplace of netscape
+ # CPPFLAGS +=-DMOZ_NOT_NET
+ # Location of MOZILLA/Netscape header files...
+ export NAN_MOZILLA_INC ?= $(LCGDIR)/mozilla/include
+ export NAN_MOZILLA_LIB ?= $(LCGDIR)/mozilla/lib/
+ # Will fall back to look in NAN_MOZILLA_INC/nspr and NAN_MOZILLA_LIB
+ # if this is not set.
+
+ export NAN_BUILDINFO ?= true
+ # Be paranoid regarding library creation (do not update archives)
+ export NAN_PARANOID ?= true
+
+ # l10n
+ #export INTERNATIONAL ?= true
+
+ # enable freetype2 support for text objects
+ #export WITH_FREETYPE2 ?= true
+
+ else
+ ifeq ($(OS),solaris)
+
+ export ID = $(shell /usr/ucb/whoami)
+ export HOST = $(shell hostname)
+ export NAN_PYTHON ?= /usr/local
+ export NAN_PYTHON_VERSION ?= 2.3
+ export NAN_PYTHON_BINARY ?= $(NAN_PYTHON)/bin/python$(NAN_PYTHON_VERSION)
+ export NAN_OPENAL ?= /usr/local
+ export NAN_FMOD ?= $(LCGDIR)/fmod
+ export NAN_JPEG ?= /usr/local
+ export NAN_PNG ?= /usr/local
+ export NAN_TIFF ?= /usr
+ export NAN_ODE ?= $(LCGDIR)/ode
+ export NAN_TERRAPLAY ?=
+ export NAN_MESA ?= /usr/src/Mesa-3.1
+ export NAN_ZLIB ?= /usr
+ export NAN_NSPR ?= $(LCGDIR)/nspr
+ export NAN_FREETYPE ?= $(LCGDIR)/freetype
+ export NAN_GETTEXT ?= $(LCGDIR)/gettext
+ export NAN_SDL ?= $(shell sdl-config --prefix)
+ export NAN_SDLLIBS ?= $(shell sdl-config --libs)
+ export NAN_SDLCFLAGS ?= $(shell sdl-config --cflags)
+
+ # Uncomment the following line to use Mozilla inplace of netscape
+ # CPPFLAGS +=-DMOZ_NOT_NET
+ # Location of MOZILLA/Netscape header files...
+ export NAN_MOZILLA_INC ?= $(LCGDIR)/mozilla/include
+ export NAN_MOZILLA_LIB ?= $(LCGDIR)/mozilla/lib/
+ # Will fall back to look in NAN_MOZILLA_INC/nspr and NAN_MOZILLA_LIB
+ # if this is not set.
+
+ export NAN_BUILDINFO ?= true
+ # Be paranoid regarding library creation (do not update archives)
+ export NAN_PARANOID ?= true
+
+ # l10n
+ #export INTERNATIONAL ?= true
+
+ # enable freetype2 support for text objects
+ #export WITH_FREETYPE2 ?= true
+
+ else
+ ifeq ($(OS),windows)
+
+ export ID = $(LOGNAME)
+ export NAN_PYTHON ?= $(LCGDIR)/python
+ export NAN_ICONV ?= $(LCGDIR)/iconv
+ export NAN_PYTHON_VERSION ?= 2.5
+ ifeq ($(FREE_WINDOWS), true)
+ export NAN_PYTHON_BINARY ?= $(NAN_PYTHON)/bin/python$(NAN_PYTHON_VERSION)
+ export NAN_FREETYPE ?= $(LCGDIR)/gcc/freetype
+ export NAN_ODE ?= $(LCGDIR)/gcc/ode
+ ifeq ($(NAN_SDL),)
+ export NAN_SDL ?= $(LCGDIR)/gcc/sdl
+ export NAN_SDLCFLAGS ?= -I$(NAN_SDL)/include
+ endif
+ else
+ export NAN_PYTHON_BINARY ?= python
+ export NAN_FREETYPE ?= $(LCGDIR)/freetype
+ export NAN_ODE ?= $(LCGDIR)/ode
+ ifeq ($(NAN_SDL),)
+ export NAN_SDL ?= $(LCGDIR)/sdl
+ export NAN_SDLCFLAGS ?= -I$(NAN_SDL)/include
+ endif
+ endif
+ export NAN_OPENAL ?= $(LCGDIR)/openal
+ export NAN_FMOD ?= $(LCGDIR)/fmod
+ export NAN_JPEG ?= $(LCGDIR)/jpeg
+ export NAN_PNG ?= $(LCGDIR)/png
+ export NAN_TIFF ?= $(LCGDIR)/tiff
+ export NAN_TERRAPLAY ?= $(LCGDIR)/terraplay
+ export NAN_MESA ?= /usr/src/Mesa-3.1
+ export NAN_ZLIB ?= $(LCGDIR)/zlib
+ export NAN_NSPR ?= $(LCGDIR)/nspr
+ export NAN_GETTEXT ?= $(LCGDIR)/gettext
+
+ # Uncomment the following line to use Mozilla inplace of netscape
+ # CPPFLAGS +=-DMOZ_NOT_NET
+ # Location of MOZILLA/Netscape header files...
+ export NAN_MOZILLA_INC ?= $(LCGDIR)/mozilla/include
+ export NAN_MOZILLA_LIB ?= $(LCGDIR)/mozilla/lib/
+ # Will fall back to look in NAN_MOZILLA_INC/nspr and NAN_MOZILLA_LIB
+ # if this is not set.
+ export NAN_PYTHON_BINARY ?= python
+ export NAN_BUILDINFO ?= true
+ # Be paranoid regarding library creation (do not update archives)
+ export NAN_PARANOID ?= true
+
+ # l10n
+ export INTERNATIONAL ?= true
+
+ # enable freetype2 support for text objects
+ export WITH_FREETYPE2 ?= true
+
+ # enable quicktime support
+ # export WITH_QUICKTIME ?= true
+
+ else # Platform not listed above
+
+ export NAN_PYTHON ?= $(LCGDIR)/python
+ export NAN_PYTHON_VERSION ?= 2.3
+ export NAN_PYTHON_BINARY ?= python
+ export NAN_OPENAL ?= $(LCGDIR)/openal
+ export NAN_FMOD ?= $(LCGDIR)/fmod
+ export NAN_JPEG ?= $(LCGDIR)/jpeg
+ export NAN_PNG ?= $(LCGDIR)/png
+ export NAN_TIFF ?= $(LCGDIR)/tiff
+ export NAN_SDL ?= $(LCGDIR)/sdl
+ export NAN_ODE ?= $(LCGDIR)/ode
+ export NAN_TERRAPLAY ?= $(LCGDIR)/terraplay
+ export NAN_MESA ?= /usr/src/Mesa-3.1
+ export NAN_ZLIB ?= $(LCGDIR)/zlib
+ export NAN_NSPR ?= $(LCGDIR)/nspr
+ export NAN_FREETYPE ?= $(LCGDIR)/freetype
+ export NAN_GETTEXT ?= $(LCGDIR)/gettext
+ export NAN_SDL ?= $(shell sdl-config --prefix)
+ export NAN_SDLLIBS ?= $(shell sdl-config --libs)
+ export NAN_SDLCFLAGS ?= $(shell sdl-config --cflags)
+
+ # Uncomment the following line to use Mozilla inplace of netscape
+ # CPPFLAGS +=-DMOZ_NOT_NET
+ # Location of MOZILLA/Netscape header files...
+ export NAN_MOZILLA_INC ?= $(LCGDIR)/mozilla/include
+ export NAN_MOZILLA_LIB ?= $(LCGDIR)/mozilla/lib/
+ # Will fall back to look in NAN_MOZILLA_INC/nspr and NAN_MOZILLA_LIB
+ # if this is not set.
+
+ export NAN_BUILDINFO ?= true
+ # Be paranoid regarding library creation (do not update archives)
+ export NAN_PARANOID ?= true
+
+ # l10n
+ #export INTERNATIONAL ?= true
+
+ # enable freetype2 support for text objects
+ #export WITH_FREETYPE2 ?= true
+
+ endif
+
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+
+# Don't want to build the gameengine?
+ifeq ($(NAN_NO_KETSJI), true)
+ export NAN_JUST_BLENDERDYNAMIC=true
+ export NAN_NO_OPENAL=true
+endif
diff --git a/source/nan_link.mk b/source/nan_link.mk
new file mode 100644
index 00000000000..e6824643a04
--- /dev/null
+++ b/source/nan_link.mk
@@ -0,0 +1,164 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# linking only
+
+include nan_definitions.mk
+
+ifdef NAN_DEBUG
+ LDFLAGS += $(NAN_DEBUG)
+endif
+
+DBG_LDFLAGS += -g
+
+ifneq (x$(DEBUG_DIR), x)
+ LDFLAGS+=$(DBG_LDFLAGS)
+else
+ LDFLAGS+=$(REL_LDFLAGS)
+endif
+
+######################## OS dependencies (alphabetic!) ################
+
+# default (overriden by windows)
+SOEXT = .so
+
+ifeq ($(OS),beos)
+ LLIBS = -L/boot/develop/lib/x86/ -lGL -lbe -L/boot/home/config/lib/
+ LLIBS += -lpython1.5
+endif
+
+ifeq ($(OS),darwin)
+ LLIBS += -lGLU -lGL
+ LLIBS += -lz -lstdc++
+ ifdef USE_OSX10.4STUBS
+ LLIBS +=-lSystemStubs
+ endif
+ LLIBS += -framework Carbon -framework AGL -framework OpenGL
+ LLIBS += -framework QuickTime -framework CoreAudio
+ LLIBS += -framework AudioUnit -framework AudioToolbox
+ LDFLAGS += -L/System/Library/Frameworks/OpenGL.framework/Libraries
+ DBG_LDFLAGS += -L/System/Library/Frameworks/OpenGL.framework/Libraries
+endif
+
+ifeq ($(OS),freebsd)
+ LLIBS = -L/usr/X11R6/lib -lX11 -lXmu -lXi -lm -lutil -lz -pthread -lc_r
+ DADD = -lGL -lGLU
+ DYNLDFLAGS = -shared $(LDFLAGS)
+ LOPTS = -Wl,--export-dynamic
+endif
+
+ifeq ($(OS),irix)
+ LDFLAGS += -mips3
+ LLIBS = -lmovieGL -lGLU -lGL -lXmu -lXext -lX11 -lc -lm -ldmedia
+ LLIBS += -lcl -laudio -ldb -lCio -lz
+ LLIBS += -lpthread
+ LLIBS += -woff 84,171
+ DYNLDFLAGS = -shared $(LDFLAGS)
+endif
+
+ifeq ($(OS),linux)
+ ifeq ($(CPU),alpha)
+ COMMENT = "MESA 3.1"
+ LLIBS = -lGL -lGLU -L/usr/X11R6/lib/ -lXmu -lXext -lX11
+ LLIBS += -lc -lm -ldl -lutil
+ LOPTS = -export-dynamic
+ endif
+ ifeq ($(CPU),$(findstring $(CPU), "i386 x86_64 ia64"))
+ COMMENT = "MESA 3.1"
+ LLIBS = -L$(NAN_MESA)/lib -L/usr/X11R6/lib -lXmu -lXext -lX11 -lXi
+ LLIBS += -lutil -lc -lm -ldl -lpthread
+# LLIBS += -L$(NAN_ODE)/lib -lode
+ LOPTS = -export-dynamic
+ DADD = -lGL -lGLU
+ SADD = $(NAN_MESA)/lib/libGL.a $(NAN_MESA)/lib/libGLU.a
+ DYNLDFLAGS = -shared $(LDFLAGS)
+ endif
+ ifeq ($(CPU),$(findstring $(CPU), "powerpc sparc64"))
+ LLIBS = -L/usr/X11R6/lib/ -lXmu -lXext -lX11 -lc -ldl -lm -lutil
+ DADD = -lGL -lGLU
+ SADD = /usr/lib/libGL.a /usr/lib/libGLU.a
+ LOPTS = -export-dynamic
+ DYNLDFLAGS = -shared $(LDFLAGS)
+ endif
+ LLIBS += -lz
+endif
+
+ifeq ($(OS),openbsd)
+ SADD = /usr/local/lib/libGL.a /usr/local/lib/libGLU.a
+ SADD += /usr/X11R6/lib/libXmu.a /usr/X11R6/lib/libXext.a
+ SADD += /usr/X11R6/lib/libX11.a /usr/lib/libm.a -pthread
+endif
+
+ifeq ($(OS),solaris)
+ LLIBS = -lGLU -lGL -lXmu -lXext -lXi -lX11 -lc -lm -ldl -lsocket -lnsl
+ DYNLDFLAGS = -shared $(LDFLAGS)
+endif
+
+ifeq ($(OS),windows)
+ EXT = .exe
+ SOEXT = .dll
+ ifeq ($(FREE_WINDOWS),true)
+ MINGWLIB = /usr/lib/w32api
+ LDFLAGS += -mwindows -mno-cygwin -mconsole
+ DADD += -L/usr/lib/w32api -lnetapi32 -lopengl32 -lglu32 -lshfolder
+ DADD += -L/usr/lib/w32api -lwinmm -lwsock32
+ ifeq ($(WITH_VERSE),true)
+ DADD += -lws2_32
+ endif
+ else
+ DADD = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib
+ DADD += advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib
+ DADD += vfw32.lib winmm.lib opengl32.lib glu32.lib largeint.lib dxguid.lib
+ DADD += libcmt.lib
+ LOPTS = /link
+ LOPTS += /NODEFAULTLIB:"libc"
+ LOPTS += /NODEFAULTLIB:"libcd"
+ LOPTS += /NODEFAULTLIB:"libcp"
+ LOPTS += /NODEFAULTLIB:"libcpd"
+ LOPTS += /NODEFAULTLIB:"python20"
+ LOPTS += /NODEFAULTLIB:"msvcrt"
+ LOPTS += /SUBSYSTEM:CONSOLE
+ LDFLAGS += /MT
+ DYNLDFLAGS = /LD
+ endif
+endif
+
+ifneq ($(OS), irix)
+ LLIBS += $(NAN_SDLLIBS)
+endif
+
+ifeq ($(WITH_ICONV),true)
+ LLIBS += $(NAN_ICONV_LIBS)
+endif
+
+ifeq ($(WITH_FFMPEG),true)
+ LLIBS += $(NAN_FFMPEGLIBS)
+endif
diff --git a/source/nan_subdirs.mk b/source/nan_subdirs.mk
new file mode 100644
index 00000000000..aab88cc292b
--- /dev/null
+++ b/source/nan_subdirs.mk
@@ -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 *****
+#
+# Bounce make to subdirectories.
+# Set DIRS, SOURCEDIR. Optionally also reacts on DIR, TESTDIRS.
+#
+
+default: all
+
+# do not add install here. install target can only be used in intern/
+# top level Makefiles
+all debug clean::
+ifdef quicky
+ @for i in $(quicky); do \
+ echo "====> $(MAKE) $@ in $$i";\
+ $(MAKE) -C $$i $@ quicky= || exit 1;\
+ done
+ $(MAKE) -C source link || exit 1
+ @echo "${quicky}"
+else
+ ifdef DIR
+ @# Make sure object toplevels are there
+ @[ -d $(NAN_OBJDIR) ] || mkdir -p $(NAN_OBJDIR)
+ @[ -d $(LCGDIR) ] || mkdir -p $(LCGDIR)
+ @[ -d $(OCGDIR) ] || mkdir -p $(OCGDIR)
+ @[ -d $(OCGDIR)/intern ] || mkdir -p $(OCGDIR)/intern
+ @[ -d $(OCGDIR)/extern ] || mkdir -p $(OCGDIR)/extern
+ @# Create object directory
+ @[ -d $(DIR) ] || mkdir -p $(DIR)
+ endif
+ ifdef SOURCEDIR
+ @for i in $(DIRS); do \
+ echo "====> $(MAKE) $@ in $(SOURCEDIR)/$$i" ;\
+ $(MAKE) -C $$i $@ || exit 1; \
+ done
+ else
+ @for i in $(DIRS); do \
+ echo "====> $(MAKE) $@ in $$i" ;\
+ $(MAKE) -C $$i $@ || exit 1; \
+ done
+ endif
+endif
+
+test::
+ ifdef TESTDIRS
+ @for i in $(TESTDIRS); do \
+ echo "====> $(MAKE) $@ in $(SOURCEDIR)/$$i" ;\
+ $(MAKE) -C $$i $@ || exit 1; \
+ done
+ endif
+
diff --git a/source/nan_warn.mk b/source/nan_warn.mk
new file mode 100644
index 00000000000..ee01f47f549
--- /dev/null
+++ b/source/nan_warn.mk
@@ -0,0 +1,169 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# NaN compiler and linker warning levels
+# On some platforms, you will be flooded with system include file warnings.
+# Use hmake to filter those away.
+#
+
+# Force the correct redefinition
+LEVEL_1_C_WARNINGS = -FIX_NAN_WARN
+LEVEL_1_CPP_WARNINGS = -FIX_NAN_WARN
+LEVEL_2_C_WARNINGS = -FIX_NAN_WARN
+LEVEL_2_CPP_WARNINGS = -FIX_NAN_WARN
+FIX_STUBS_WARNINGS = -FIX_NAN_WARN
+
+########################################################################
+# Level 1: basic C warnings.
+ifeq ($(CC),gcc)
+ LEVEL_1_C_WARNINGS = -Wall
+ LEVEL_1_C_WARNINGS += -Wno-char-subscripts
+else
+ ifeq ($(CC),cc)
+ ifeq ($(OS),irix)
+ # MIPSpro Compilers
+ #
+ # Irix warning info
+ #
+ # 1001 # the source file does not end w/ a newline
+ # 1110 # unreachable statement
+ # 1201 # trailing comma in enums is nonstandard
+ # 1209 # constant controlling expressions
+ # 1355 # extra semicolon is ignored
+ # 1424 # unreferenced template paramaters
+ # 1681 # virtual function override
+ # 3201 # unreferenced formal paramaters
+ #
+
+ LEVEL_1_C_WARNINGS = -fullwarn -woff 1001,1110,1201,1209,1355,1424,1681,3201
+ endif
+ endif
+ ifeq ($(OS),windows)
+ # Microsoft Compilers and cl_wrapper.pl
+ LEVEL_1_C_WARNINGS = -Wall
+ endif
+endif
+
+# Level 1: basic CPP warnings.
+ifeq ($(CCC),g++)
+ LEVEL_1_CPP_WARNINGS = -Wall
+ LEVEL_1_CPP_WARNINGS += -Wno-reorder
+else
+ ifeq ($(CCC),CC)
+ ifeq ($(OS),irix)
+ # MIPSpro Compilers
+ # see warning descriptions above
+ LEVEL_1_CPP_WARNINGS = -woff 1001,1110,1201,1209,1355,1424,1681,3201
+ endif
+ endif
+ ifeq ($(OS),windows)
+ # Microsoft Compilers and cl_wrapper.pl
+ LEVEL_1_CPP_WARNINGS = -Wall
+ endif
+endif
+
+########################################################################
+# Level 2: paranoia level C warnings.
+# DO NOT REUSE LEVEL_1_ DEFINES.
+ifeq ($(CC),gcc)
+ LEVEL_2_C_WARNINGS = -Wall
+ LEVEL_2_C_WARNINGS += -W
+ # deliberately enable char-subscript warnings
+ LEVEL_2_C_WARNINGS += -Wshadow
+ LEVEL_2_C_WARNINGS += -Wpointer-arith
+ LEVEL_2_C_WARNINGS += -Wbad-function-cast
+ LEVEL_2_C_WARNINGS += -Wcast-qual
+ LEVEL_2_C_WARNINGS += -Wcast-align
+ LEVEL_2_C_WARNINGS += -Waggregate-return
+ LEVEL_2_C_WARNINGS += -Wstrict-prototypes
+ LEVEL_2_C_WARNINGS += -Wmissing-prototypes
+ LEVEL_2_C_WARNINGS += -Wmissing-declarations
+ LEVEL_2_C_WARNINGS += -Wnested-externs
+ LEVEL_2_C_WARNINGS += -Wredundant-decls
+else
+ ifeq ($(CC),cc)
+ ifeq ($(OS),irix)
+ # MIPSpro Compilers
+ # see warning descriptions above
+ LEVEL_2_C_WARNINGS = -fullwarn -woff 1001,1209,1424,3201
+ endif
+ ifeq ($(OS),solaris)
+ # Forte / Sun WorkShop Compilers
+ LEVEL_2_C_WARNINGS = -v
+ endif
+ endif
+ ifeq ($(OS),windows)
+ # Microsoft Compilers and cl_wrapper.pl
+ LEVEL_2_C_WARNINGS = -Wall
+ endif
+endif
+
+# Level 2: paranoia level CPP warnings.
+# DO NOT REUSE LEVEL_1_ DEFINES.
+ifeq ($(CCC),g++)
+ LEVEL_2_CPP_WARNINGS = -Wall
+ LEVEL_2_CPP_WARNINGS += -W
+ # deliberately enable char-subscript warnings
+ LEVEL_2_CPP_WARNINGS += -Wshadow
+ LEVEL_2_CPP_WARNINGS += -Wpointer-arith
+ LEVEL_2_CPP_WARNINGS += -Wcast-qual
+ LEVEL_2_CPP_WARNINGS += -Wcast-align
+ # deliberately disable aggregate-return warnings
+ LEVEL_2_CPP_WARNINGS += -Wredundant-decls
+ LEVEL_2_CPP_WARNINGS += -Wreorder
+ LEVEL_2_CPP_WARNINGS += -Wctor-dtor-privacy
+ LEVEL_2_CPP_WARNINGS += -Wnon-virtual-dtor
+ #LEVEL_2_CPP_WARNINGS += -Wold-style-cast
+ LEVEL_2_CPP_WARNINGS += -Woverloaded-virtual
+ LEVEL_2_CPP_WARNINGS += -Wsign-promo
+ LEVEL_2_CPP_WARNINGS += -Wsynth
+else
+ ifeq ($(CCC),CC)
+ ifeq ($(OS),irix)
+ # MIPSpro Compilers
+ # see warning descriptions above
+ LEVEL_2_CPP_WARNINGS = -fullwarn -woff 1209,1424,3201
+ endif
+ endif
+ ifeq ($(OS),windows)
+ # Microsoft Compilers and cl_wrapper.pl
+ LEVEL_2_CPP_WARNINGS = -Wall
+ endif
+endif
+
+########################################################################
+# stubs warning fix
+ifeq ($(CC),gcc)
+ FIX_STUBS_WARNINGS = -Wno-unused
+else
+ FIX_STUBS_WARNINGS =
+endif
+